2023-05-13 11:20:56 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace App\Jobs;
|
|
|
|
|
|
|
|
use Carbon\Carbon;
|
|
|
|
use Illuminate\Bus\Queueable;
|
|
|
|
use Illuminate\Contracts\Queue\ShouldBeUnique;
|
|
|
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
|
|
use Illuminate\Foundation\Bus\Dispatchable;
|
|
|
|
use Illuminate\Queue\InteractsWithQueue;
|
|
|
|
use Illuminate\Queue\SerializesModels;
|
2023-05-13 13:51:27 +00:00
|
|
|
use Illuminate\Support\Facades\Config;
|
2023-05-13 11:20:56 +00:00
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
|
2023-05-13 13:51:27 +00:00
|
|
|
use App\Models\{Account,Invoice,Payment,PaymentItem,ProviderToken,Site};
|
2023-05-13 12:01:43 +00:00
|
|
|
use Intuit\Models\Payment as PaymentModel;
|
2023-05-13 11:20:56 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Synchronise payments with our payments.
|
|
|
|
*
|
|
|
|
* This will:
|
|
|
|
* + Create/Update the payment in our system
|
2024-01-31 22:51:58 +00:00
|
|
|
* + Associate the payment to the same invoice in our system
|
2023-05-13 11:20:56 +00:00
|
|
|
*/
|
|
|
|
class AccountingPaymentSync implements ShouldQueue
|
|
|
|
{
|
|
|
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
|
|
|
|
|
|
private const LOGKEY = 'JPS';
|
|
|
|
|
2023-05-13 12:01:43 +00:00
|
|
|
private PaymentModel $pmi;
|
2023-05-13 11:20:56 +00:00
|
|
|
private ProviderToken $to;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Create a new job instance.
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
2023-05-13 12:01:43 +00:00
|
|
|
public function __construct(ProviderToken $to,PaymentModel $pmi)
|
2023-05-13 11:20:56 +00:00
|
|
|
{
|
|
|
|
$this->pmi = $pmi;
|
|
|
|
$this->to = $to;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Execute the job.
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
* @throws \Exception
|
|
|
|
*/
|
|
|
|
public function handle()
|
|
|
|
{
|
2023-05-13 13:51:27 +00:00
|
|
|
// @todo Can this be automatically determined?
|
|
|
|
$site = Site::findOrFail($this->to->site_id);
|
|
|
|
Config::set('site',$site);
|
|
|
|
|
2023-05-13 11:20:56 +00:00
|
|
|
// See if we are already linked
|
|
|
|
if (($x=$this->to->provider->payments->where('pivot.ref',$this->pmi->id))->count() === 1) {
|
|
|
|
$o = $x->pop();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
// Find the account
|
|
|
|
$ao = Account::select('accounts.*')
|
|
|
|
->join('account__provider',['account__provider.account_id'=>'accounts.id'])
|
|
|
|
->where('provider_oauth_id',$this->to->provider_oauth_id)
|
|
|
|
->where('ref',$this->pmi->account_ref)
|
|
|
|
->single();
|
|
|
|
|
|
|
|
if (! $ao) {
|
|
|
|
Log::alert(sprintf('%s:Account not found for payment [%s:%d]',self::LOGKEY,$this->pmi->id,$this->pmi->account_ref));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the payment
|
|
|
|
$o = new Payment;
|
|
|
|
$o->account_id = $ao->id;
|
|
|
|
$o->site_id = $ao->site_id; // @todo Automatically determine
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the payment details
|
|
|
|
$o->paid_at = $this->pmi->date_paid;
|
|
|
|
$o->active = TRUE;
|
|
|
|
$o->checkout_id = 2; // @todo
|
|
|
|
$o->total_amt = $this->pmi->total_amt;
|
|
|
|
$o->notes = 'Imported from Intuit';
|
|
|
|
$o->save();
|
|
|
|
|
|
|
|
Log::info(sprintf('%s:Recording payment [%s:%3.2f]',self::LOGKEY,$this->pmi->id,$this->pmi->total_amt));
|
|
|
|
|
|
|
|
$o->providers()->syncWithoutDetaching([
|
|
|
|
$this->to->provider->id => [
|
|
|
|
'ref' => $this->pmi->id,
|
|
|
|
'synctoken' => $this->pmi->synctoken,
|
|
|
|
'created_at'=>Carbon::create($this->pmi->created_at),
|
|
|
|
'updated_at'=>Carbon::create($this->pmi->updated_at),
|
|
|
|
'site_id'=>$this->to->site_id,
|
|
|
|
],
|
|
|
|
]);
|
|
|
|
|
|
|
|
// Load the invoice that this payment pays
|
|
|
|
$invoices = collect();
|
|
|
|
foreach ($this->pmi->lines() as $item => $amount) {
|
|
|
|
$invoice = Invoice::select('invoices.*')
|
|
|
|
->join('invoice__provider',['invoice__provider.invoice_id'=>'invoices.id'])
|
|
|
|
->where('provider_oauth_id',$this->to->provider_oauth_id)
|
|
|
|
->where('ref',$item)
|
|
|
|
->single();
|
|
|
|
|
|
|
|
$invoices->put($item,$invoice);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete existing paid invoices that are no longer paid
|
|
|
|
foreach ($o->items as $pio)
|
|
|
|
if ($invoices->pluck('id')->search($pio->invoice_id) === FALSE)
|
|
|
|
$pio->delete();
|
|
|
|
|
|
|
|
// Update payment items
|
|
|
|
foreach ($this->pmi->lines() as $item => $amount) {
|
|
|
|
if (! $invoices->has($item)) {
|
|
|
|
Log::alert(sprintf('%s:Invoice [%s] not recorded, payment not assigned',self::LOGKEY,$item));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$io = $invoices->get($item);
|
|
|
|
|
|
|
|
// If the payment item already exists
|
|
|
|
if (($x=$o->items->where('invoice_id',$io->id))->count()) {
|
|
|
|
$pio = $x->pop();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
$pio = new PaymentItem;
|
|
|
|
$pio->invoice_id = $io->id;
|
|
|
|
$pio->site_id = $io->site_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
$pio->amount = $amount;
|
|
|
|
$o->items()->save($pio);
|
|
|
|
}
|
|
|
|
|
|
|
|
Log::alert(sprintf('%s:Payment updated [%s:%s]',self::LOGKEY,$o->id,$this->pmi->id));
|
|
|
|
}
|
|
|
|
}
|