From a87b8d1e99fba313d0a7e8a78882e8bed3aaaaa0 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 11 Nov 2022 14:52:50 +1100 Subject: [PATCH 1/4] EPC QR Codes WIP --- app/Console/Commands/BackupUpdate.php | 35 +++++++++--- app/Filters/ProductFilters.php | 3 ++ app/Helpers/Epc/EpcQrGenerator.php | 78 +++++++++++++++++++++++++++ app/Jobs/Company/CompanyImport.php | 2 +- 4 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 app/Helpers/Epc/EpcQrGenerator.php diff --git a/app/Console/Commands/BackupUpdate.php b/app/Console/Commands/BackupUpdate.php index e5bff73c5423..b1ad1ddff5a8 100644 --- a/app/Console/Commands/BackupUpdate.php +++ b/app/Console/Commands/BackupUpdate.php @@ -15,6 +15,7 @@ use App\Libraries\MultiDB; use App\Models\Backup; use App\Models\Company; use App\Models\Design; +use App\Models\Document; use Illuminate\Console\Command; use Illuminate\Support\Facades\Storage; use stdClass; @@ -76,29 +77,51 @@ class BackupUpdate extends Command set_time_limit(0); //logos - - Company::query() - ->cursor() + Company::cursor() ->each(function ($company){ - $logo = @file_get_contents($company->present()->logo()); + $company_logo = $company->present()->logo(); + + if($company_logo == 'https://invoicing.co/images/new_logo.png') + return; + + $logo = @file_get_contents($company_logo); if($logo){ - $path = str_replace("https://object.invoicing.co/", "", $company->present()->logo()); + $path = str_replace("https://objects.invoicing.co/", "", $company->present()->logo()); $path = str_replace("https://v5-at-backup.us-southeast-1.linodeobjects.com/", "", $path); Storage::disk($this->option('disk'))->put($path, $logo); - } }); //documents + Document::cursor() + ->each(function ($document){ + + $doc_bin = $document->getFile(); + + if($doc_bin) + Storage::disk($this->option('disk'))->put($document->url, $doc_bin); + + }); //backups + Backup::cursor() + ->each(function ($backup){ + + $backup_bin = Storage::disk('s3')->get($backup->filename); + + if($backup_bin) + Storage::disk($this->option('disk'))->put($backup->filename, $backup_bin); + + }); + + } } diff --git a/app/Filters/ProductFilters.php b/app/Filters/ProductFilters.php index a406b6521f19..4e4ed2f500d8 100644 --- a/app/Filters/ProductFilters.php +++ b/app/Filters/ProductFilters.php @@ -102,6 +102,9 @@ class ProductFilters extends QueryFilters { $sort_col = explode('|', $sort); + if(!is_array($sort_col)) + return $this->builder; + return $this->builder->orderBy($sort_col[0], $sort_col[1]); } diff --git a/app/Helpers/Epc/EpcQrGenerator.php b/app/Helpers/Epc/EpcQrGenerator.php new file mode 100644 index 000000000000..adf36dc83887 --- /dev/null +++ b/app/Helpers/Epc/EpcQrGenerator.php @@ -0,0 +1,78 @@ + 'BCD', + 'version' => 2, + 'characterSet' => 1, + 'identification' => 'SCT', + 'bic' => '', + 'purpose' => '', + + ]; + + public function __construct(protected Company $company, protected Invoice $invoice, protected float $amount){} + + public function getQrCode() + { + + $renderer = new ImageRenderer( + new RendererStyle(200), + new SvgImageBackEnd() + ); + $writer = new Writer($renderer); + + $qr = $writer->writeString($this->encodeMessage()); + + return " + {$qr}"; + + } + + public function encodeMessage() + { + + return rtrim(implode("\n", array( + $this->sepa['serviceTag'], + sprintf('%03d', $this->sepa['version']), + $this->sepa['characterSet'], + $this->sepa['identification'], + $this->sepa['bic'], + $this->company->present()->name(), + $this->company?->custom_fields?->company1 ?: '', + $this->formatMoney($this->amount), + $this->sepa['purpose'], + substr($this->invoice->number,0,34), + substr($this->invoice->public_notes,0,139), + '' + )), "\n"); + + } + + private function formatMoney($value) { + return sprintf('EUR%s', number_format($value, 2, '.', '')); + } +} \ No newline at end of file diff --git a/app/Jobs/Company/CompanyImport.php b/app/Jobs/Company/CompanyImport.php index 8cac0d230176..67964eefa18f 100644 --- a/app/Jobs/Company/CompanyImport.php +++ b/app/Jobs/Company/CompanyImport.php @@ -1107,7 +1107,7 @@ class CompanyImport implements ShouldQueue $storage_url = (object)$this->getObject('storage_url', true); - if(!Storage::exists($new_document->url)){ + if(!Storage::exists($new_document->url) && is_string($storage_url)){ $url = $storage_url . $new_document->url; From 569fa064e37e17c723ba65fecd75552c3b5bbf98 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 11 Nov 2022 15:16:03 +1100 Subject: [PATCH 2/4] Additional logging for Checkout transactions --- app/PaymentDrivers/CheckoutCom/Utilities.php | 4 ++-- app/PaymentDrivers/CheckoutComPaymentDriver.php | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/PaymentDrivers/CheckoutCom/Utilities.php b/app/PaymentDrivers/CheckoutCom/Utilities.php index 3c9caef92b25..f8e960fe56c2 100644 --- a/app/PaymentDrivers/CheckoutCom/Utilities.php +++ b/app/PaymentDrivers/CheckoutCom/Utilities.php @@ -87,9 +87,9 @@ trait Utilities $error_message = ''; - if (array_key_exists('actions', $_payment) && array_key_exists('response_summary', end($_payment['actions']))) { + if (is_array($_payment) && array_key_exists('actions', $_payment) && array_key_exists('response_summary', end($_payment['actions']))) { $error_message = end($_payment['actions'])['response_summary']; - } elseif (array_key_exists('status', $_payment)) { + } elseif (is_array($_payment) && array_key_exists('status', $_payment)) { $error_message = $_payment['status']; } diff --git a/app/PaymentDrivers/CheckoutComPaymentDriver.php b/app/PaymentDrivers/CheckoutComPaymentDriver.php index 9e19ac2fe6bb..6801d8f0ff41 100644 --- a/app/PaymentDrivers/CheckoutComPaymentDriver.php +++ b/app/PaymentDrivers/CheckoutComPaymentDriver.php @@ -438,7 +438,7 @@ class CheckoutComPaymentDriver extends BaseDriver $this->init(); $this->setPaymentHash($request->getPaymentHash()); - //11-08-2022 check the user is autenticated + //11-08-2022 check the user is authenticated if (!Auth::guard('contact')->check()) { $client = $request->getClient(); auth()->guard('contact')->loginUsingId($client->contacts()->first()->id, true); @@ -455,6 +455,8 @@ class CheckoutComPaymentDriver extends BaseDriver return $this->processUnsuccessfulPayment($payment); } } catch (CheckoutApiException | Exception $e) { + nlog("checkout"); + nlog($e->getMessage()); return $this->processInternallyFailedPayment($this, $e); } } From dacde3358ab561905dc40192c42cfe9132f9c3f6 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Fri, 11 Nov 2022 15:28:49 +1100 Subject: [PATCH 3/4] Add Bank Services class --- .../Controllers/BankIntegrationController.php | 2 +- .../Controllers/BankTransactionController.php | 2 +- app/Jobs/Bank/MatchBankTransactions.php | 2 +- app/Jobs/Bank/ProcessBankTransactions.php | 4 +- app/Models/BankTransaction.php | 20 +---- .../BankTransactionRepository.php | 2 +- app/Services/Bank/BankMatchingService.php | 84 +++++++++++++++++++ app/Services/Bank/BankService.php | 72 +++++----------- app/Services/Bank/ProcessBankRule.php | 27 ++++++ 9 files changed, 140 insertions(+), 75 deletions(-) create mode 100644 app/Services/Bank/BankMatchingService.php create mode 100644 app/Services/Bank/ProcessBankRule.php diff --git a/app/Http/Controllers/BankIntegrationController.php b/app/Http/Controllers/BankIntegrationController.php index 750505c24feb..774aa97057e8 100644 --- a/app/Http/Controllers/BankIntegrationController.php +++ b/app/Http/Controllers/BankIntegrationController.php @@ -24,7 +24,7 @@ use App\Http\Requests\BankIntegration\UpdateBankIntegrationRequest; use App\Jobs\Bank\ProcessBankTransactions; use App\Models\BankIntegration; use App\Repositories\BankIntegrationRepository; -use App\Services\Bank\BankService; +use App\Services\Bank\BankMatchingService; use App\Transformers\BankIntegrationTransformer; use App\Utils\Traits\MakesHash; use Illuminate\Http\Request; diff --git a/app/Http/Controllers/BankTransactionController.php b/app/Http/Controllers/BankTransactionController.php index 13fb7be803dd..901f1812a071 100644 --- a/app/Http/Controllers/BankTransactionController.php +++ b/app/Http/Controllers/BankTransactionController.php @@ -27,7 +27,7 @@ use App\Http\Requests\Import\PreImportRequest; use App\Jobs\Bank\MatchBankTransactions; use App\Models\BankTransaction; use App\Repositories\BankTransactionRepository; -use App\Services\Bank\BankService; +use App\Services\Bank\BankMatchingService; use App\Transformers\BankTransactionTransformer; use App\Utils\Traits\MakesHash; use Illuminate\Http\Request; diff --git a/app/Jobs/Bank/MatchBankTransactions.php b/app/Jobs/Bank/MatchBankTransactions.php index 14ec163292ca..bb366453c155 100644 --- a/app/Jobs/Bank/MatchBankTransactions.php +++ b/app/Jobs/Bank/MatchBankTransactions.php @@ -26,7 +26,7 @@ use App\Models\Currency; use App\Models\ExpenseCategory; use App\Models\Invoice; use App\Models\Payment; -use App\Services\Bank\BankService; +use App\Services\Bank\BankMatchingService; use App\Utils\Ninja; use App\Utils\Traits\GeneratesCounter; use App\Utils\Traits\MakesHash; diff --git a/app/Jobs/Bank/ProcessBankTransactions.php b/app/Jobs/Bank/ProcessBankTransactions.php index d213be664a7a..74d996f0fd14 100644 --- a/app/Jobs/Bank/ProcessBankTransactions.php +++ b/app/Jobs/Bank/ProcessBankTransactions.php @@ -16,7 +16,7 @@ use App\Libraries\MultiDB; use App\Models\BankIntegration; use App\Models\BankTransaction; use App\Models\Company; -use App\Services\Bank\BankService; +use App\Services\Bank\BankMatchingService; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; @@ -79,7 +79,7 @@ class ProcessBankTransactions implements ShouldQueue } while($this->stop_loop); - BankService::dispatch($this->company->id, $this->company->db); + BankMatchingService::dispatch($this->company->id, $this->company->db); } diff --git a/app/Models/BankTransaction.php b/app/Models/BankTransaction.php index 45ff86ecd2f8..7092da3f89b1 100644 --- a/app/Models/BankTransaction.php +++ b/app/Models/BankTransaction.php @@ -13,6 +13,7 @@ namespace App\Models; use App\Models\Filterable; use App\Models\Invoice; +use App\Services\Bank\BankService; use App\Utils\Traits\MakesHash; use Illuminate\Database\Eloquent\SoftDeletes; @@ -98,22 +99,9 @@ class BankTransaction extends BaseModel return $this->belongsTo(Account::class)->withTrashed(); } - - public function matchInvoiceNumber() + public function service() :BankService { - - if(strlen($this->description) > 1) - { - - $i = Invoice::where('company_id', $this->company_id) - ->whereIn('status_id', [1,2,3]) - ->where('is_deleted', 0) - ->where('number', 'LIKE', '%'.$this->description.'%') - ->first(); - - return $i ?: false; - } - - return false; + return new BankService($this); } + } \ No newline at end of file diff --git a/app/Repositories/BankTransactionRepository.php b/app/Repositories/BankTransactionRepository.php index ac53b4aee437..186f8c67ead8 100644 --- a/app/Repositories/BankTransactionRepository.php +++ b/app/Repositories/BankTransactionRepository.php @@ -31,7 +31,7 @@ class BankTransactionRepository extends BaseRepository $bank_transaction->save(); - if($bank_transaction->base_type == 'CREDIT' && $invoice = $bank_transaction->matchInvoiceNumber()) + if($bank_transaction->base_type == 'CREDIT' && $invoice = $bank_transaction->service()->matchInvoiceNumber()) { $bank_transaction->invoice_ids = $invoice->hashed_id; $bank_transaction->status_id = BankTransaction::STATUS_MATCHED; diff --git a/app/Services/Bank/BankMatchingService.php b/app/Services/Bank/BankMatchingService.php new file mode 100644 index 000000000000..b466a95cfcd8 --- /dev/null +++ b/app/Services/Bank/BankMatchingService.php @@ -0,0 +1,84 @@ +company_id = $company_id; + $this->db = $db; + } + + public function handle() + { + + MultiDB::setDb($this->db); + + $this->company = Company::find($this->company_id); + + $this->invoices = Invoice::where('company_id', $this->company->id) + ->whereIn('status_id', [1,2,3]) + ->where('is_deleted', 0) + ->get(); + + $this->match(); + } + + private function match() + { + + BankTransaction::where('company_id', $this->company->id) + ->where('status_id', BankTransaction::STATUS_UNMATCHED) + ->cursor() + ->each(function ($bt){ + + $invoice = $this->invoices->first(function ($value, $key) use ($bt){ + + return str_contains($bt->description, $value->number); + + }); + + if($invoice) + { + $bt->invoice_ids = $invoice->hashed_id; + $bt->status_id = BankTransaction::STATUS_MATCHED; + $bt->save(); + } + + }); + } + + +} diff --git a/app/Services/Bank/BankService.php b/app/Services/Bank/BankService.php index ad15ddd21352..7a7f50759191 100644 --- a/app/Services/Bank/BankService.php +++ b/app/Services/Bank/BankService.php @@ -11,74 +11,40 @@ namespace App\Services\Bank; -use App\Libraries\MultiDB; use App\Models\BankTransaction; -use App\Models\Company; use App\Models\Invoice; -use Illuminate\Bus\Queueable; -use Illuminate\Contracts\Queue\ShouldQueue; -use Illuminate\Foundation\Bus\Dispatchable; -use Illuminate\Queue\InteractsWithQueue; -use Illuminate\Queue\SerializesModels; +use App\Services\Bank\ProcessBankRule; -class BankService implements ShouldQueue +class BankService { - use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - private $company_id; + public function __construct(public BankTransaction $bank_transaction) {} - private Company $company; - private $db; - - private $invoices; - - public $deleteWhenMissingModels = true; - - public function __construct($company_id, $db) - { - $this->company_id = $company_id; - $this->db = $db; - } - - public function handle() + public function matchInvoiceNumber() { - MultiDB::setDb($this->db); + if(strlen($this->bank_transaction->description) > 1) + { - $this->company = Company::find($this->company_id); + $i = Invoice::where('company_id', $this->bank_transaction->company_id) + ->whereIn('status_id', [1,2,3]) + ->where('is_deleted', 0) + ->where('number', 'LIKE', '%'.$this->bank_transaction->description.'%') + ->first(); - $this->invoices = Invoice::where('company_id', $this->company->id) - ->whereIn('status_id', [1,2,3]) - ->where('is_deleted', 0) - ->get(); + return $i ?: false; + } + + return false; - $this->match(); } - private function match() + public function processRule($rule) { + (new ProcessBankRule($this->bank_transaction, $rule))->run(); - BankTransaction::where('company_id', $this->company->id) - ->where('status_id', BankTransaction::STATUS_UNMATCHED) - ->cursor() - ->each(function ($bt){ - - $invoice = $this->invoices->first(function ($value, $key) use ($bt){ - - return str_contains($bt->description, $value->number); - - }); - - if($invoice) - { - $bt->invoice_ids = $invoice->hashed_id; - $bt->status_id = BankTransaction::STATUS_MATCHED; - $bt->save(); - } - - }); + return $this; } - -} +} \ No newline at end of file diff --git a/app/Services/Bank/ProcessBankRule.php b/app/Services/Bank/ProcessBankRule.php new file mode 100644 index 000000000000..ffeedbb1f1fe --- /dev/null +++ b/app/Services/Bank/ProcessBankRule.php @@ -0,0 +1,27 @@ + Date: Sat, 12 Nov 2022 09:00:54 +1100 Subject: [PATCH 4/4] Handle checkout failures --- app/PaymentDrivers/CheckoutCom/Utilities.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/PaymentDrivers/CheckoutCom/Utilities.php b/app/PaymentDrivers/CheckoutCom/Utilities.php index f8e960fe56c2..d9d2ff4b3fbb 100644 --- a/app/PaymentDrivers/CheckoutCom/Utilities.php +++ b/app/PaymentDrivers/CheckoutCom/Utilities.php @@ -92,11 +92,14 @@ trait Utilities } elseif (is_array($_payment) && array_key_exists('status', $_payment)) { $error_message = $_payment['status']; } + else { + $error_message = 'Error processing payment.'; + } $this->getParent()->sendFailureMail($error_message); $message = [ - 'server_response' => $_payment, + 'server_response' => $_payment ?: 'Server did not return any response. Most likely failed before payment was created.', 'data' => $this->getParent()->payment_hash->data, ]; @@ -110,7 +113,7 @@ trait Utilities ); if ($throw_exception) { - throw new PaymentFailed($_payment['status'].' '.$error_message, 500); + throw new PaymentFailed($error_message, 500); } }