Use transaction when marking an invoice as paid

This commit is contained in:
David Bomba 2022-08-29 18:15:50 +10:00
parent e961eb58fa
commit 384ce1fa8d
9 changed files with 66 additions and 25 deletions

View File

@ -237,6 +237,10 @@ class PaymentEmailEngine extends BaseEmailEngine
$data['$invoice.po_number'] = ['value' => $this->formatPoNumber(), 'label' => ctrans('texts.po_number')]; $data['$invoice.po_number'] = ['value' => $this->formatPoNumber(), 'label' => ctrans('texts.po_number')];
$data['$poNumber'] = &$data['$invoice.po_number']; $data['$poNumber'] = &$data['$invoice.po_number'];
$data['$payment.status'] = ['value' => $this->payment->stringStatus($this->payment->status_id), 'label' => ctrans('texts.payment_status')]; $data['$payment.status'] = ['value' => $this->payment->stringStatus($this->payment->status_id), 'label' => ctrans('texts.payment_status')];
$data['$invoices.amount'] = ['value' => $this->formatInvoiceField('amount'), 'label' => ctrans('texts.invoices')];
$data['$invoices.balance'] = ['value' => $this->formatInvoiceField('balance'), 'label' => ctrans('texts.invoices')];
$data['$invoices.due_date'] = ['value' => $this->formatInvoiceField('due_date'), 'label' => ctrans('texts.invoices')];
$data['$invoices.po_number'] = ['value' => $this->formatInvoiceField('po_number'), 'label' => ctrans('texts.invoices')];
$arrKeysLength = array_map('strlen', array_keys($data)); $arrKeysLength = array_map('strlen', array_keys($data));
array_multisort($arrKeysLength, SORT_DESC, $data); array_multisort($arrKeysLength, SORT_DESC, $data);
@ -244,6 +248,22 @@ class PaymentEmailEngine extends BaseEmailEngine
return $data; return $data;
} }
private function formatInvoiceField($field)
{
$invoice = '';
foreach ($this->payment->invoices as $invoice) {
$invoice_field = $invoice->{$field};
$invoice .= ctrans('texts.invoice_number_short') . "{$invoice->number} {$invoice_field}";
}
return $invoice;
}
private function formatInvoice() private function formatInvoice()
{ {
$invoice = ''; $invoice = '';
@ -282,11 +302,15 @@ class PaymentEmailEngine extends BaseEmailEngine
$invoice_list = '<br><br>'; $invoice_list = '<br><br>';
foreach ($this->payment->invoices as $invoice) { foreach ($this->payment->invoices as $invoice) {
$invoice_list .= ctrans('texts.po_number')." {$invoice->po_number} <br>";
if(strlen($invoice->po_number) > 1)
$invoice_list .= ctrans('texts.po_number')." {$invoice->po_number} <br>";
$invoice_list .= ctrans('texts.invoice_number_short')." {$invoice->number} <br>"; $invoice_list .= ctrans('texts.invoice_number_short')." {$invoice->number} <br>";
$invoice_list .= ctrans('texts.invoice_amount').' '.Number::formatMoney($invoice->pivot->amount, $this->client).'<br>'; $invoice_list .= ctrans('texts.invoice_amount').' '.Number::formatMoney($invoice->pivot->amount, $this->client).'<br>';
$invoice_list .= ctrans('texts.invoice_balance').' '.Number::formatMoney($invoice->fresh()->balance, $this->client).'<br>'; $invoice_list .= ctrans('texts.invoice_balance').' '.Number::formatMoney($invoice->fresh()->balance, $this->client).'<br>';
$invoice_list .= '-----<br>'; $invoice_list .= '-----<br>';
} }
return $invoice_list; return $invoice_list;

View File

@ -41,20 +41,37 @@ class MarkPaid extends AbstractService
public function run() public function run()
{ {
if ($this->invoice->status_id == Invoice::STATUS_DRAFT) {
$this->invoice->service()->markSent()->save();
}
/*Don't double pay*/ /*Don't double pay*/
if ($this->invoice->status_id == Invoice::STATUS_PAID) { if ($this->invoice->status_id == Invoice::STATUS_PAID) {
return $this->invoice; return $this->invoice;
} }
if ($this->invoice->status_id == Invoice::STATUS_DRAFT) {
$this->invoice->service()->markSent()->save();
}
$payable_balance = $this->invoice->balance;
\DB::connection(config('database.default'))->transaction(function () use($payable_balance) {
$this->invoice = Invoice::where('id', $this->invoice->id)->lockForUpdate()->first();
$this->invoice
->service()
->setExchangeRate()
->updateBalance($payable_balance * -1)
->updatePaidToDate($payable_balance)
->setStatus(Invoice::STATUS_PAID)
->save();
}, 1);
/* Create Payment */ /* Create Payment */
$payment = PaymentFactory::create($this->invoice->company_id, $this->invoice->user_id); $payment = PaymentFactory::create($this->invoice->company_id, $this->invoice->user_id);
$payment->amount = $this->invoice->balance; $payment->amount = $payable_balance;
$payment->applied = $this->invoice->balance; $payment->applied = $payable_balance;
$payment->status_id = Payment::STATUS_COMPLETED; $payment->status_id = Payment::STATUS_COMPLETED;
$payment->client_id = $this->invoice->client_id; $payment->client_id = $this->invoice->client_id;
$payment->transaction_reference = ctrans('texts.manual_entry'); $payment->transaction_reference = ctrans('texts.manual_entry');
@ -79,20 +96,20 @@ class MarkPaid extends AbstractService
/* Create a payment relationship to the invoice entity */ /* Create a payment relationship to the invoice entity */
$payment->invoices()->attach($this->invoice->id, [ $payment->invoices()->attach($this->invoice->id, [
'amount' => $payment->amount, 'amount' => $payable_balance,
]); ]);
event('eloquent.created: App\Models\Payment', $payment); event('eloquent.created: App\Models\Payment', $payment);
$this->invoice->next_send_date = null; $this->invoice->next_send_date = null;
$this->invoice // $this->invoice
->service() // ->service()
->setExchangeRate() // ->setExchangeRate()
->updateBalance($payment->amount * -1) // ->updateBalance($payment->amount * -1)
->updatePaidToDate($payment->amount) // ->updatePaidToDate($payment->amount)
->setStatus(Invoice::STATUS_PAID) // ->setStatus(Invoice::STATUS_PAID)
->save(); // ->save();
$this->invoice $this->invoice
->service() ->service()
@ -101,7 +118,7 @@ class MarkPaid extends AbstractService
->save(); ->save();
$payment->ledger() $payment->ledger()
->updatePaymentBalance($payment->amount * -1); ->updatePaymentBalance($payable_balance * -1);
\DB::connection(config('database.default'))->transaction(function () use ($payment) { \DB::connection(config('database.default'))->transaction(function () use ($payment) {

View File

@ -42,9 +42,9 @@ class ZeroCostProduct extends AbstractService
$invoice = $this->subscription->service()->createInvoice($this->data); $invoice = $this->subscription->service()->createInvoice($this->data);
$invoice->service() $invoice = $invoice->service()
->markPaid() ->markPaid()
->save(); ->save();
$redirect_url = "/client/invoices/{$invoice->hashed_id}"; $redirect_url = "/client/invoices/{$invoice->hashed_id}";

View File

@ -72,7 +72,7 @@ class EntityPaidToDateTest extends TestCase
$this->assertEquals($invoice->balance, 20); $this->assertEquals($invoice->balance, 20);
$invoice->service()->markPaid()->save(); $invoice = $invoice->service()->markPaid()->save();
$this->assertEquals($invoice->paid_to_date, 20); $this->assertEquals($invoice->paid_to_date, 20);
} }
@ -81,7 +81,7 @@ class EntityPaidToDateTest extends TestCase
{ {
$invoice = $this->bootNewInvoice(); $invoice = $this->bootNewInvoice();
$invoice->service()->markPaid()->save(); $invoice = $invoice->service()->markPaid()->save();
$this->assertEquals(20, $invoice->paid_to_date); $this->assertEquals(20, $invoice->paid_to_date);

View File

@ -185,7 +185,7 @@ class InvoiceAmountPaymentTest extends TestCase
$this->assertEquals(25, $invoice->balance); $this->assertEquals(25, $invoice->balance);
$this->assertEquals(25, $invoice->amount); $this->assertEquals(25, $invoice->amount);
$invoice->service()->markPaid()->save(); $invoice = $invoice->service()->markPaid()->save();
$invoice->fresh(); $invoice->fresh();

View File

@ -1422,7 +1422,7 @@ class PaymentTest extends TestCase
$this->assertEquals(10, $this->invoice->balance); $this->assertEquals(10, $this->invoice->balance);
$this->assertEquals(10, $this->invoice->client->fresh()->balance); $this->assertEquals(10, $this->invoice->client->fresh()->balance);
$this->invoice->service()->markPaid()->save(); $this->invoice = $this->invoice->service()->markPaid()->save();
$this->assertEquals(0, $this->invoice->balance); $this->assertEquals(0, $this->invoice->balance);
$this->assertEquals(0, $this->invoice->client->balance); $this->assertEquals(0, $this->invoice->client->balance);

View File

@ -40,7 +40,7 @@ class GoogleAnalyticsTest extends TestCase
$invoice = $this->invoice; $invoice = $this->invoice;
$client = $this->client; $client = $this->client;
$invoice->service()->markPaid()->save(); $invoice = $invoice->service()->markPaid()->save();
$payment = $invoice->payments->first(); $payment = $invoice->payments->first();

View File

@ -45,7 +45,7 @@ class InvoiceActionsTest extends TestCase
{ {
$this->withoutEvents(); $this->withoutEvents();
$this->invoice->service()->markPaid()->save(); $this->invoice = $this->invoice->service()->markPaid()->save();
$this->assertFalse($this->invoiceDeletable($this->invoice)); $this->assertFalse($this->invoiceDeletable($this->invoice));
$this->assertTrue($this->invoiceReversable($this->invoice)); $this->assertTrue($this->invoiceReversable($this->invoice));

View File

@ -82,7 +82,7 @@ class SubscriptionsCalcTest extends TestCase
$this->assertFalse($sub_calculator->isPaidUp()); $this->assertFalse($sub_calculator->isPaidUp());
$invoice->service()->markPaid()->save(); $invoice = $invoice->service()->markPaid()->save();
$this->assertTrue($sub_calculator->isPaidUp()); $this->assertTrue($sub_calculator->isPaidUp());