diff --git a/composer.lock b/composer.lock index 2493991eceb3..39e5e4356514 100644 --- a/composer.lock +++ b/composer.lock @@ -485,16 +485,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.281.15", + "version": "3.282.0", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "8256b827274966396eccf8ad391ce88d7c53ffa0" + "reference": "79a3ed5bb573f592823f8b1cffe0dbac3132e6b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/8256b827274966396eccf8ad391ce88d7c53ffa0", - "reference": "8256b827274966396eccf8ad391ce88d7c53ffa0", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/79a3ed5bb573f592823f8b1cffe0dbac3132e6b4", + "reference": "79a3ed5bb573f592823f8b1cffe0dbac3132e6b4", "shasum": "" }, "require": { @@ -574,9 +574,9 @@ "support": { "forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.281.15" + "source": "https://github.com/aws/aws-sdk-php/tree/3.282.0" }, - "time": "2023-09-27T18:06:59+00:00" + "time": "2023-09-28T18:09:20+00:00" }, { "name": "bacon/bacon-qr-code", @@ -4287,16 +4287,16 @@ }, { "name": "laravel/framework", - "version": "v10.25.1", + "version": "v10.25.2", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "cd0a440f43eaaad247d6f6575d3782c156ec913c" + "reference": "6014dd456b414b305fb0b408404efdcec18e64bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/cd0a440f43eaaad247d6f6575d3782c156ec913c", - "reference": "cd0a440f43eaaad247d6f6575d3782c156ec913c", + "url": "https://api.github.com/repos/laravel/framework/zipball/6014dd456b414b305fb0b408404efdcec18e64bc", + "reference": "6014dd456b414b305fb0b408404efdcec18e64bc", "shasum": "" }, "require": { @@ -4483,7 +4483,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-09-27T01:29:32+00:00" + "time": "2023-09-28T14:08:59+00:00" }, { "name": "laravel/prompts", @@ -9698,16 +9698,16 @@ }, { "name": "setasign/fpdi", - "version": "v2.4.1", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/Setasign/FPDI.git", - "reference": "f4ba73e5bc053ccc90b81717c5df1cb2ea7bae7b" + "reference": "ecf0459643ec963febfb9a5d529dcd93656006a4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Setasign/FPDI/zipball/f4ba73e5bc053ccc90b81717c5df1cb2ea7bae7b", - "reference": "f4ba73e5bc053ccc90b81717c5df1cb2ea7bae7b", + "url": "https://api.github.com/repos/Setasign/FPDI/zipball/ecf0459643ec963febfb9a5d529dcd93656006a4", + "reference": "ecf0459643ec963febfb9a5d529dcd93656006a4", "shasum": "" }, "require": { @@ -9758,7 +9758,7 @@ ], "support": { "issues": "https://github.com/Setasign/FPDI/issues", - "source": "https://github.com/Setasign/FPDI/tree/v2.4.1" + "source": "https://github.com/Setasign/FPDI/tree/v2.5.0" }, "funding": [ { @@ -9766,7 +9766,7 @@ "type": "tidelift" } ], - "time": "2023-07-27T08:12:09+00:00" + "time": "2023-09-28T10:46:27+00:00" }, { "name": "shopify/shopify-api", @@ -16711,16 +16711,16 @@ }, { "name": "sebastian/complexity", - "version": "3.0.1", + "version": "3.1.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "c70b73893e10757af9c6a48929fa6a333b56a97a" + "reference": "68cfb347a44871f01e33ab0ef8215966432f6957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/c70b73893e10757af9c6a48929fa6a333b56a97a", - "reference": "c70b73893e10757af9c6a48929fa6a333b56a97a", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/68cfb347a44871f01e33ab0ef8215966432f6957", + "reference": "68cfb347a44871f01e33ab0ef8215966432f6957", "shasum": "" }, "require": { @@ -16733,7 +16733,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "3.0-dev" + "dev-main": "3.1-dev" } }, "autoload": { @@ -16757,7 +16757,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", "security": "https://github.com/sebastianbergmann/complexity/security/policy", - "source": "https://github.com/sebastianbergmann/complexity/tree/3.0.1" + "source": "https://github.com/sebastianbergmann/complexity/tree/3.1.0" }, "funding": [ { @@ -16765,7 +16765,7 @@ "type": "github" } ], - "time": "2023-08-31T09:55:53+00:00" + "time": "2023-09-28T11:50:59+00:00" }, { "name": "sebastian/diff", diff --git a/tests/Feature/Template/TemplateTest.php b/tests/Feature/Template/TemplateTest.php index 0d86917b54e1..502a5f8e338c 100644 --- a/tests/Feature/Template/TemplateTest.php +++ b/tests/Feature/Template/TemplateTest.php @@ -13,16 +13,20 @@ namespace Tests\Feature\Template; use Tests\TestCase; use App\Utils\Ninja; +use App\Utils\Number; +use App\Models\Credit; use App\Models\Design; use App\Models\Invoice; +use App\Models\Payment; use App\Utils\HtmlEngine; use Tests\MockAccountData; +use App\Utils\Traits\MakesDates; use App\Services\PdfMaker\PdfMaker; use Illuminate\Support\Facades\App; use App\Jobs\Entity\CreateEntityPdf; +use App\Services\Template\TemplateService; use App\Services\PdfMaker\Design as PdfDesignModel; use App\Services\PdfMaker\Design as PdfMakerDesign; -use App\Services\Template\TemplateService; use Illuminate\Routing\Middleware\ThrottleRequests; use Illuminate\Foundation\Testing\DatabaseTransactions; @@ -34,6 +38,7 @@ class TemplateTest extends TestCase { use DatabaseTransactions; use MockAccountData; + use MakesDates; private string $body = ' @@ -170,6 +175,219 @@ class TemplateTest extends TestCase ThrottleRequests::class ); + } + + public function testDataMaps() + { + + Invoice::factory()->count(10)->create([ + 'company_id' => $this->company->id, + 'user_id' => $this->user->id, + 'client_id' => $this->client->id, + 'status_id' => Invoice::STATUS_SENT, + 'amount' => 100, + 'balance' => 100, + ]); + + $invoices = Invoice::orderBy('id','desc')->where('client_id', $this->client->id)->take(10)->get()->map(function($c){ + return $c->service()->markSent()->applyNumber()->save(); + })->map(function ($i){ + return ['invoice_id' => $i->hashed_id, 'amount' => rand(0, $i->balance)]; + })->toArray(); + + Credit::factory()->count(2)->create([ + 'company_id' => $this->company->id, + 'user_id' => $this->user->id, + 'client_id' => $this->client->id, + 'status_id' => Invoice::STATUS_SENT, + 'amount' => 50, + 'balance' => 50, + ]); + + $credits = Credit::orderBy('id', 'desc')->where('client_id', $this->client->id)->take(2)->get()->map(function($c){ + return $c->service()->markSent()->applyNumber()->save(); + })->map(function ($i) { + return ['credit_id' => $i->hashed_id, 'amount' => rand(0, $i->balance)]; + })->toArray(); + + $data = [ + 'invoices' => $invoices, + 'credits' => $credits, + 'date' => now()->format('Y-m-d'), + 'client_id' => $this->client->hashed_id, + 'transaction_reference' => 'My Batch Payment', + 'type_id' => "5", + ]; + + $response = $this->withHeaders([ + 'X-API-SECRET' => config('ninja.api_secret'), + 'X-API-TOKEN' => $this->token, + ])->postJson('/api/v1/payments/', $data); + + $response->assertStatus(200); + + $arr = $response->json(); + + // $p = Payment::with('client','invoices','paymentables','credits') + // ->where('id', $this->decodePrimaryKey($arr['data']['id']))->first(); + + // nlog($p->toArray()); + + $p = Payment::with('client','invoices','paymentables','credits') + ->where('id', $this->decodePrimaryKey($arr['data']['id'])) + ->cursor() + ->map(function ($payment){ + + $this->transformPayment($payment); + + })->toArray(); + + $this->assertIsArray($data); + + $invoices = Invoice::with('client','payments','credits') + ->orderBy('id','desc') + ->where('client_id', $this->client->id) + ->take(10) + ->get() + ->map(function($invoice){ + + $payments = $invoice->payments->map(function ($payment){ + return $this->transformPayment($payment); + })->toArray(); + + return [ + 'amount' => Number::formatMoney($invoice->amount, $invoice->client), + 'balance' => Number::formatMoney($invoice->balance, $invoice->client), + 'balance_raw' => $invoice->balance, + 'number' => $invoice->number ?: '', + 'discount' => $invoice->discount, + 'po_number' => $invoice->po_number ?: '', + 'date' => $this->translateDate($invoice->date, $invoice->client->date_format(), $invoice->client->locale()), + 'last_sent_date' => $this->translateDate($invoice->last_sent_date, $invoice->client->date_format(), $invoice->client->locale()), + 'next_send_date' => $this->translateDate($invoice->next_send_date, $invoice->client->date_format(), $invoice->client->locale()), + 'due_date' => $this->translateDate($invoice->due_date, $invoice->client->date_format(), $invoice->client->locale()), + 'terms' => $invoice->terms ?: '', + 'public_notes' => $invoice->public_notes ?: '', + 'private_notes' => $invoice->private_notes ?: '', + 'uses_inclusive_taxes' => (bool) $invoice->uses_inclusive_taxes, + 'tax_name1' => $invoice->tax_name1 ?? '', + 'tax_rate1' => (float) $invoice->tax_rate1, + 'tax_name2' => $invoice->tax_name2 ?? '', + 'tax_rate2' => (float) $invoice->tax_rate2, + 'tax_name3' => $invoice->tax_name3 ?? '', + 'tax_rate3' => (float) $invoice->tax_rate3, + 'total_taxes' => Number::formatMoney($invoice->total_taxes, $invoice->client), + 'total_taxes_raw' => $invoice->total_taxes, + 'is_amount_discount' => (bool) $invoice->is_amount_discount ?? false, + 'footer' => $invoice->footer ?? '', + 'partial' => $invoice->partial ?? 0, + 'partial_due_date' => $this->translateDate($invoice->partial_due_date, $invoice->client->date_format(), $invoice->client->locale()), + 'custom_value1' => (string) $invoice->custom_value1 ?: '', + 'custom_value2' => (string) $invoice->custom_value2 ?: '', + 'custom_value3' => (string) $invoice->custom_value3 ?: '', + 'custom_value4' => (string) $invoice->custom_value4 ?: '', + 'custom_surcharge1' => (float) $invoice->custom_surcharge1, + 'custom_surcharge2' => (float) $invoice->custom_surcharge2, + 'custom_surcharge3' => (float) $invoice->custom_surcharge3, + 'custom_surcharge4' => (float) $invoice->custom_surcharge4, + 'exchange_rate' => (float) $invoice->exchange_rate, + 'custom_surcharge_tax1' => (bool) $invoice->custom_surcharge_tax1, + 'custom_surcharge_tax2' => (bool) $invoice->custom_surcharge_tax2, + 'custom_surcharge_tax3' => (bool) $invoice->custom_surcharge_tax3, + 'custom_surcharge_tax4' => (bool) $invoice->custom_surcharge_tax4, + 'line_items' => $invoice->line_items ?: (array) [], + 'reminder1_sent' => $this->translateDate($invoice->reminder1_sent, $invoice->client->date_format(), $invoice->client->locale()), + 'reminder2_sent' => $this->translateDate($invoice->reminder2_sent, $invoice->client->date_format(), $invoice->client->locale()), + 'reminder3_sent' => $this->translateDate($invoice->reminder3_sent, $invoice->client->date_format(), $invoice->client->locale()), + 'reminder_last_sent' => $this->translateDate($invoice->reminder_last_sent, $invoice->client->date_format(), $invoice->client->locale()), + 'paid_to_date' => Number::formatMoney($invoice->paid_to_date, $invoice->client), + 'auto_bill_enabled' => (bool) $invoice->auto_bill_enabled, + 'client' => [ + 'name' => $invoice->client->present()->name(), + 'balance' => $invoice->client->balance, + 'payment_balance' => $invoice->client->payment_balance, + 'credit_balance' => $invoice->client->credit_balance, + ], + 'payments' => $payments + ]; + })->toArray(); + + $this->assertIsArray($invoices); + + } + + private function transformPayment(Payment $payment): array + { + + $data = []; + + $credits = $payment->credits->map(function ($credit) use ($payment) { + return [ + 'credit' => $credit->number, + 'amount_raw' => $credit->pivot->amount, + 'refunded_raw' => $credit->pivot->refunded, + 'net_raw' => $credit->pivot->amount - $credit->pivot->refunded, + 'amount' => Number::formatMoney($credit->pivot->amount, $payment->client), + 'refunded' => Number::formatMoney($credit->pivot->refunded, $payment->client), + 'net' => Number::formatMoney($credit->pivot->amount - $credit->pivot->refunded, $payment->client), + 'is_credit' => true, + 'created_at' => $this->translateDate($credit->pivot->created_at, $payment->client->date_format(), $payment->client->locale()), + 'updated_at' => $this->translateDate($credit->pivot->updated_at, $payment->client->date_format(), $payment->client->locale()), + 'timestamp' => $credit->pivot->created_at->timestamp, + ]; + }); + + $pivot = $payment->invoices->map(function ($invoice) use ($payment) { + return [ + 'invoice' => $invoice->number, + 'amount_raw' => $invoice->pivot->amount, + 'refunded_raw' => $invoice->pivot->refunded, + 'net_raw' => $invoice->pivot->amount - $invoice->pivot->refunded, + 'amount' => Number::formatMoney($invoice->pivot->amount, $payment->client), + 'refunded' => Number::formatMoney($invoice->pivot->refunded, $payment->client), + 'net' => Number::formatMoney($invoice->pivot->amount - $invoice->pivot->refunded, $payment->client), + 'is_credit' => false, + 'created_at' => $this->translateDate($invoice->pivot->created_at, $payment->client->date_format(), $payment->client->locale()), + 'updated_at' => $this->translateDate($invoice->pivot->updated_at, $payment->client->date_format(), $payment->client->locale()), + 'timestamp' => $invoice->pivot->created_at->timestamp, + ]; + })->merge($credits)->sortBy('timestamp')->toArray(); + + return [ + 'status' => $payment->stringStatus($payment->status_id), + 'badge' => $payment->badgeForStatus($payment->status_id), + 'amount' => Number::formatMoney($payment->amount, $payment->client), + 'applied' => Number::formatMoney($payment->applied, $payment->client), + 'balance' => Number::formatMoney(($payment->amount - $payment->refunded - $payment->applied), $payment->client), + 'refunded' => Number::formatMoney($payment->refunded, $payment->client), + 'amount_raw' => $payment->amount, + 'applied_raw' => $payment->applied, + 'refunded_raw' => $payment->refunded, + 'balance_raw' => ($payment->amount - $payment->refunded - $payment->applied), + 'date' => $this->translateDate($payment->date, $payment->client->date_format(), $payment->client->locale()), + 'method' => $payment->translatedType(), + 'currency' => $payment->currency->code, + 'exchange_rate' => $payment->exchange_rate, + 'transaction_reference' => $payment->transaction_reference, + 'is_manual' => $payment->is_manual, + 'number' => $payment->number, + 'custom_value1' => $payment->custom_value1 ?? '', + 'custom_value2' => $payment->custom_value2 ?? '', + 'custom_value3' => $payment->custom_value3 ?? '', + 'custom_value4' => $payment->custom_value4 ?? '', + 'client' => [ + 'name' => $payment->client->present()->name(), + 'balance' => $payment->client->balance, + 'payment_balance' => $payment->client->payment_balance, + 'credit_balance' => $payment->client->credit_balance, + ], + 'paymentables' => $pivot, + ]; + + return $data; + + + } public function testVariableResolutionViaTransformersForPaymentsInStatements() @@ -216,6 +434,8 @@ class TemplateTest extends TestCase $design_model = Design::find(2); $replicated_design = $design_model->replicate(); + $replicated_design->company_id = $this->company->id; + $replicated_design->user_id = $this->user->id; $design = $replicated_design->design; $design->body .= $this->payments_body; $replicated_design->design = $design; @@ -238,6 +458,8 @@ class TemplateTest extends TestCase $design_model = Design::find(2); $replicated_design = $design_model->replicate(); + $replicated_design->company_id = $this->company->id; + $replicated_design->user_id = $this->user->id; $design = $replicated_design->design; $design->body .= $this->nested_body; $replicated_design->design = $design; @@ -269,6 +491,8 @@ class TemplateTest extends TestCase $design_model = Design::find(2); $replicated_design = $design_model->replicate(); + $replicated_design->company_id = $this->company->id; + $replicated_design->user_id = $this->user->id; $design = $replicated_design->design; $design->body .= $this->body; $replicated_design->design = $design; @@ -298,8 +522,9 @@ class TemplateTest extends TestCase public function testTemplateServiceBuild() { $design_model = Design::find(2); - $replicated_design = $design_model->replicate(); + $replicated_design->company_id = $this->company->id; + $replicated_design->user_id = $this->user->id; $design = $replicated_design->design; $design->body .= $this->body; $replicated_design->design = $design; @@ -321,6 +546,8 @@ class TemplateTest extends TestCase $design_model = Design::find(2); $replicated_design = $design_model->replicate(); + $replicated_design->company_id = $this->company->id; + $replicated_design->user_id = $this->user->id; $design = $replicated_design->design; $design->body .= $this->body; $replicated_design->design = $design; @@ -336,6 +563,8 @@ class TemplateTest extends TestCase $design_model = Design::find(2); $replicated_design = $design_model->replicate(); + $replicated_design->company_id = $this->company->id; + $replicated_design->user_id = $this->user->id; $design = $replicated_design->design; $design->body .= $this->body; $replicated_design->design = $design;