diff --git a/app/Helpers/Bank/Yodlee/Transformer/AccountTransformer.php b/app/Helpers/Bank/Yodlee/Transformer/AccountTransformer.php index 1f045a58f8be..4afe7850798d 100644 --- a/app/Helpers/Bank/Yodlee/Transformer/AccountTransformer.php +++ b/app/Helpers/Bank/Yodlee/Transformer/AccountTransformer.php @@ -89,7 +89,7 @@ class AccountTransformer implements AccountTransformerInterface 'account_type' => $account->CONTAINER, 'account_name' => $account->accountName, 'account_status' => $account->accountStatus, - 'account_number' => $account->accountNumber, + 'account_number' => '**** ' . substr($account->accountNumber, -7), 'provider_account_id' => $account->providerAccountId, 'provider_id' => $account->providerId, 'provider_name' => $account->providerName, diff --git a/app/Http/Controllers/Bank/YodleeController.php b/app/Http/Controllers/Bank/YodleeController.php index b743822c0a8c..af7269e3ad07 100644 --- a/app/Http/Controllers/Bank/YodleeController.php +++ b/app/Http/Controllers/Bank/YodleeController.php @@ -114,7 +114,192 @@ class YodleeController extends BaseController }); + } + + /** + * Process Yodlee Refresh Webhook. + * + * + * @OA\Post( + * path="/api/v1/yodlee/refresh", + * operationId="yodleeRefreshWebhook", + * tags={"yodlee"}, + * summary="Processing webhooks from Yodlee", + * description="Notifies the system when a data point can be refreshed", + * @OA\Parameter(ref="#/components/parameters/X-Api-Secret"), + * @OA\Parameter(ref="#/components/parameters/X-Api-Token"), + * @OA\Parameter(ref="#/components/parameters/X-Requested-With"), + * @OA\Parameter(ref="#/components/parameters/include"), + * @OA\Response( + * response=200, + * description="", + * @OA\Header(header="X-MINIMUM-CLIENT-VERSION", ref="#/components/headers/X-MINIMUM-CLIENT-VERSION"), + * @OA\Header(header="X-RateLimit-Remaining", ref="#/components/headers/X-RateLimit-Remaining"), + * @OA\Header(header="X-RateLimit-Limit", ref="#/components/headers/X-RateLimit-Limit"), + * @OA\JsonContent(ref="#/components/schemas/Credit"), + * ), + * @OA\Response( + * response=422, + * description="Validation error", + * @OA\JsonContent(ref="#/components/schemas/ValidationError"), + * + * ), + * @OA\Response( + * response="default", + * description="Unexpected Error", + * @OA\JsonContent(ref="#/components/schemas/Error"), + * ), + * ) + */ + + /* + { + "event":{ + "info":"REFRESH.PROCESS_COMPLETED", + "loginName":"fri21", + "data":{ + "providerAccount":[ + { + "id":10995860, + "providerId":16441, + "isManual":false, + "createdDate":"2017-12-22T05:47:35Z", + "aggregationSource":"USER", + "status":"SUCCESS", + "requestId":"NSyMGo+R4dktywIu3hBIkc3PgWA=", + "dataset":[ + { + "name":"BASIC_AGG_DATA", + "additionalStatus":"AVAILABLE_DATA_RETRIEVED", + "updateEligibility":"ALLOW_UPDATE", + "lastUpdated":"2017-12-22T05:48:16Z", + "lastUpdateAttempt":"2017-12-22T05:48:16Z" + } + ] + } + ] + } + } +}*/ + public function refreshWebhook(Request $request) + { +//we should ignore this one + nlog("yodlee refresh"); + nlog($request->all()); + + return response()->json(['message' => 'Success'], 200); + + // + + // return response()->json(['message' => 'Unauthorized'], 403); + } + +/* +{ + "event":{ + "notificationId":"63c73475-4db5-49ef-8553-8303337ca7c3", + "info":"LATEST_BALANCE_UPDATES", + "loginName":"user1", + "data":{ + "providerAccountId":658552, + "latestBalanceEvent":[ + { + "accountId":12345, + "status":"SUCCESS" + }, + { + "accountId":12346, + "status":"FAILED" + } + ] + } + } +} +*/ + public function balanceWebhook(Request $request) + { + + nlog("yodlee refresh"); + nlog($request->all()); + + return response()->json(['message' => 'Success'], 200); + + // + + // return response()->json(['message' => 'Unauthorized'], 403); + } + +/* +{ + "event":{ + "data":[ + { + "autoRefresh":{ + "additionalStatus":"SCHEDULED", + "status":"ENABLED" + }, + "accountIds":[ + 1112645899, + 1112645898 + ], + "loginName":"YSL1555332811628", + "providerAccountId":11381459 + } + ], + "notificationTime":"2019-06-14T04:49:39Z", + "notificationId":"4e672150-156048777", + "info":"AUTO_REFRESH_UPDATES" + } +} +*/ + public function refreshUpdatesWebhook(Request $request) + { +//notifies a user if there are problems with yodlee accessing the data + nlog("update refresh"); + nlog($request->all()); + + return response()->json(['message' => 'Success'], 200); + + // + + // return response()->json(['message' => 'Unauthorized'], 403); + } + + +/* +"event": { + "notificationId": "64b7ed1a-1530523285", + "info": "DATA_UPDATES.USER_DATA", + "data": { + "userCount": 1, + "fromDate": "2017-11-10T10:18:44Z", + "toDate": "2017-11-10T11:18:43Z", + "userData": [{ + "user": { + "loginName": "YSL1484052178554" + }, + "links": [{ + "methodType": "GET", + "rel": "getUserData", + "href": "dataExtracts/userData?fromDate=2017-11-10T10:18:44Z&toDate=2017-11-10T11:18:43Z&loginName=YSL1484052178554" + }] + }] + } +} +*/ + public function dataUpdatesWebhook(Request $request) + { +//this is the main hook we use for notifications + + nlog("data refresh"); + nlog($request->all()); + + return response()->json(['message' => 'Success'], 200); + + // + + // return response()->json(['message' => 'Unauthorized'], 403); } } diff --git a/app/Http/Controllers/InvoiceController.php b/app/Http/Controllers/InvoiceController.php index bea85e642f30..7a9a199a84e0 100644 --- a/app/Http/Controllers/InvoiceController.php +++ b/app/Http/Controllers/InvoiceController.php @@ -19,6 +19,7 @@ use App\Factory\CloneInvoiceToQuoteFactory; use App\Factory\InvoiceFactory; use App\Filters\InvoiceFilters; use App\Http\Requests\Invoice\ActionInvoiceRequest; +use App\Http\Requests\Invoice\BulkInvoiceRequest; use App\Http\Requests\Invoice\CreateInvoiceRequest; use App\Http\Requests\Invoice\DestroyInvoiceRequest; use App\Http\Requests\Invoice\EditInvoiceRequest; @@ -546,11 +547,11 @@ class InvoiceController extends BaseController * ), * ) */ - public function bulk() + public function bulk(BulkInvoiceRequest $request) { - $action = request()->input('action'); + $action = $request->input('action'); - $ids = request()->input('ids'); + $ids = $request->input('ids'); if(Ninja::isHosted() && (stripos($action, 'email') !== false) && !auth()->user()->company()->account->account_sms_verified) return response(['message' => 'Please verify your account to send emails.'], 400); diff --git a/app/Http/Requests/Credit/StoreCreditRequest.php b/app/Http/Requests/Credit/StoreCreditRequest.php index 6258893af516..6c9dec07a176 100644 --- a/app/Http/Requests/Credit/StoreCreditRequest.php +++ b/app/Http/Requests/Credit/StoreCreditRequest.php @@ -59,7 +59,13 @@ class StoreCreditRequest extends Request $rules['number'] = ['nullable', Rule::unique('credits')->where('company_id', auth()->user()->company()->id)]; $rules['discount'] = 'sometimes|numeric'; $rules['is_amount_discount'] = ['boolean']; - + $rules['tax_rate1'] = 'bail|sometimes|numeric'; + $rules['tax_rate2'] = 'bail|sometimes|numeric'; + $rules['tax_rate3'] = 'bail|sometimes|numeric'; + $rules['tax_name1'] = 'bail|sometimes|string|nullable'; + $rules['tax_name2'] = 'bail|sometimes|string|nullable'; + $rules['tax_name3'] = 'bail|sometimes|string|nullable'; + if ($this->invoice_id) { $rules['invoice_id'] = new ValidInvoiceCreditRule(); } diff --git a/app/Http/Requests/Credit/UpdateCreditRequest.php b/app/Http/Requests/Credit/UpdateCreditRequest.php index ae10af3b75e5..09f7c09f7593 100644 --- a/app/Http/Requests/Credit/UpdateCreditRequest.php +++ b/app/Http/Requests/Credit/UpdateCreditRequest.php @@ -59,7 +59,13 @@ class UpdateCreditRequest extends Request $rules['line_items'] = 'array'; $rules['discount'] = 'sometimes|numeric'; $rules['is_amount_discount'] = ['boolean']; - + $rules['tax_rate1'] = 'bail|sometimes|numeric'; + $rules['tax_rate2'] = 'bail|sometimes|numeric'; + $rules['tax_rate3'] = 'bail|sometimes|numeric'; + $rules['tax_name1'] = 'bail|sometimes|string|nullable'; + $rules['tax_name2'] = 'bail|sometimes|string|nullable'; + $rules['tax_name3'] = 'bail|sometimes|string|nullable'; + return $rules; } diff --git a/app/Http/Requests/Invoice/ActionInvoiceRequest.php b/app/Http/Requests/Invoice/ActionInvoiceRequest.php index ff19f7e547c7..599488bf3cb9 100644 --- a/app/Http/Requests/Invoice/ActionInvoiceRequest.php +++ b/app/Http/Requests/Invoice/ActionInvoiceRequest.php @@ -70,4 +70,4 @@ class ActionInvoiceRequest extends Request 'action' => $this->error_msg, ]; } -} +} \ No newline at end of file diff --git a/app/Http/Requests/Invoice/BulkInvoiceRequest.php b/app/Http/Requests/Invoice/BulkInvoiceRequest.php new file mode 100644 index 000000000000..3610158d911a --- /dev/null +++ b/app/Http/Requests/Invoice/BulkInvoiceRequest.php @@ -0,0 +1,32 @@ + 'required|string', + 'ids' => 'required' + ]; + } + +} diff --git a/app/Http/Requests/Invoice/StoreInvoiceRequest.php b/app/Http/Requests/Invoice/StoreInvoiceRequest.php index d6afd0de5642..f52bb016aabe 100644 --- a/app/Http/Requests/Invoice/StoreInvoiceRequest.php +++ b/app/Http/Requests/Invoice/StoreInvoiceRequest.php @@ -69,7 +69,13 @@ class StoreInvoiceRequest extends Request $rules['line_items'] = 'array'; $rules['discount'] = 'sometimes|numeric'; - + $rules['tax_rate1'] = 'bail|sometimes|numeric'; + $rules['tax_rate2'] = 'bail|sometimes|numeric'; + $rules['tax_rate3'] = 'bail|sometimes|numeric'; + $rules['tax_name1'] = 'bail|sometimes|string|nullable'; + $rules['tax_name2'] = 'bail|sometimes|string|nullable'; + $rules['tax_name3'] = 'bail|sometimes|string|nullable'; + return $rules; } diff --git a/app/Http/Requests/Invoice/UpdateInvoiceRequest.php b/app/Http/Requests/Invoice/UpdateInvoiceRequest.php index 9dffb29ff6ca..46d50f3cdf0e 100644 --- a/app/Http/Requests/Invoice/UpdateInvoiceRequest.php +++ b/app/Http/Requests/Invoice/UpdateInvoiceRequest.php @@ -62,6 +62,12 @@ class UpdateInvoiceRequest extends Request $rules['line_items'] = 'array'; $rules['discount'] = 'sometimes|numeric'; $rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())]; + $rules['tax_rate1'] = 'bail|sometimes|numeric'; + $rules['tax_rate2'] = 'bail|sometimes|numeric'; + $rules['tax_rate3'] = 'bail|sometimes|numeric'; + $rules['tax_name1'] = 'bail|sometimes|string|nullable'; + $rules['tax_name2'] = 'bail|sometimes|string|nullable'; + $rules['tax_name3'] = 'bail|sometimes|string|nullable'; return $rules; } diff --git a/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php index c220fca528fd..0d6925dc0d59 100644 --- a/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php +++ b/app/Http/Requests/RecurringInvoice/StoreRecurringInvoiceRequest.php @@ -58,7 +58,14 @@ class StoreRecurringInvoiceRequest extends Request $rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())]; $rules['number'] = new UniqueRecurringInvoiceNumberRule($this->all()); - + + $rules['tax_rate1'] = 'bail|sometimes|numeric'; + $rules['tax_rate2'] = 'bail|sometimes|numeric'; + $rules['tax_rate3'] = 'bail|sometimes|numeric'; + $rules['tax_name1'] = 'bail|sometimes|string|nullable'; + $rules['tax_name2'] = 'bail|sometimes|string|nullable'; + $rules['tax_name3'] = 'bail|sometimes|string|nullable'; + return $rules; } diff --git a/app/Http/Requests/RecurringInvoice/UpdateRecurringInvoiceRequest.php b/app/Http/Requests/RecurringInvoice/UpdateRecurringInvoiceRequest.php index b13dc0efc0c7..0a719fbc308a 100644 --- a/app/Http/Requests/RecurringInvoice/UpdateRecurringInvoiceRequest.php +++ b/app/Http/Requests/RecurringInvoice/UpdateRecurringInvoiceRequest.php @@ -54,7 +54,13 @@ class UpdateRecurringInvoiceRequest extends Request } $rules['project_id'] = ['bail', 'sometimes', new ValidProjectForClient($this->all())]; - + $rules['tax_rate1'] = 'bail|sometimes|numeric'; + $rules['tax_rate2'] = 'bail|sometimes|numeric'; + $rules['tax_rate3'] = 'bail|sometimes|numeric'; + $rules['tax_name1'] = 'bail|sometimes|string|nullable'; + $rules['tax_name2'] = 'bail|sometimes|string|nullable'; + $rules['tax_name3'] = 'bail|sometimes|string|nullable'; + return $rules; } diff --git a/app/PaymentDrivers/Stripe/ImportCustomers.php b/app/PaymentDrivers/Stripe/ImportCustomers.php index 8ecd3dbb5f32..3661091b4956 100644 --- a/app/PaymentDrivers/Stripe/ImportCustomers.php +++ b/app/PaymentDrivers/Stripe/ImportCustomers.php @@ -64,6 +64,7 @@ class ImportCustomers } $starting_after = end($customers->data)['id']; + } while ($customers->has_more); } diff --git a/app/Services/Payment/UpdateInvoicePayment.php b/app/Services/Payment/UpdateInvoicePayment.php index ddc2fd03993e..4efbeddb715c 100644 --- a/app/Services/Payment/UpdateInvoicePayment.php +++ b/app/Services/Payment/UpdateInvoicePayment.php @@ -63,16 +63,6 @@ class UpdateInvoicePayment } $client->service()->updateBalanceAndPaidToDate($paid_amount*-1, $paid_amount); - - // \DB::connection(config('database.default'))->transaction(function () use($client, $paid_amount){ - - // $update_client = Client::withTrashed()->where('id', $client->id)->lockForUpdate()->first(); - - // $update_client->paid_to_date += $paid_amount; - // $update_client->balance -= $paid_amount; - // $update_client->save(); - - // }, 1); /* Need to determine here is we have an OVER payment - if YES only apply the max invoice amount */ if($paid_amount > $invoice->partial && $paid_amount > $invoice->balance) @@ -86,8 +76,6 @@ class UpdateInvoicePayment $invoice = $invoice->service() ->clearPartial() - // ->updateBalance($paid_amount * -1) - // ->updatePaidToDate($paid_amount) ->updateStatus() ->touchPdf() ->save(); diff --git a/routes/api.php b/routes/api.php index 8219f65630fb..44dc83425a27 100644 --- a/routes/api.php +++ b/routes/api.php @@ -14,6 +14,7 @@ use App\Http\Controllers\AccountController; use App\Http\Controllers\ActivityController; use App\Http\Controllers\Auth\ForgotPasswordController; use App\Http\Controllers\Auth\LoginController; +use App\Http\Controllers\Bank\YodleeController; use App\Http\Controllers\BankIntegrationController; use App\Http\Controllers\BankTransactionController; use App\Http\Controllers\BaseController; @@ -361,4 +362,10 @@ Route::post('api/v1/get_migration_account', [HostedMigrationController::class, ' Route::post('api/v1/confirm_forwarding', [HostedMigrationController::class, 'confirmForwarding'])->middleware('guest')->middleware('throttle:100,1'); Route::post('api/v1/process_webhook', [AppleController::class, 'process_webhook'])->middleware('throttle:1000,1'); Route::post('api/v1/confirm_purchase', [AppleController::class, 'confirm_purchase'])->middleware('throttle:1000,1'); +Route::post('api/v1/yodlee/refresh', [YodleeController::class, 'refreshWebhook'])->middleware('throttle:100,1'); +Route::post('api/v1/yodlee/data_updates', [YodleeController::class, 'dataUpdatesWebhook'])->middleware('throttle:100,1'); +Route::post('api/v1/yodlee/refresh_updates', [YodleeController::class, 'refreshUpdatesWebhook'])->middleware('throttle:100,1'); +Route::post('api/v1/yodlee/balance', [YodleeController::class, 'balanceWebhook'])->middleware('throttle:100,1'); + + Route::fallback([BaseController::class, 'notFound']); \ No newline at end of file