diff --git a/app/Console/Commands/Intuit/InvoiceAdd.php b/app/Console/Commands/Intuit/InvoiceAdd.php index 9e8b935..2ccecb2 100644 --- a/app/Console/Commands/Intuit/InvoiceAdd.php +++ b/app/Console/Commands/Intuit/InvoiceAdd.php @@ -5,19 +5,20 @@ namespace App\Console\Commands\Intuit; use Illuminate\Console\Command; use Intuit\Jobs\AccountingInvoiceUpdate; use Intuit\Models\Invoice as AccInvoice; +use Intuit\Traits\ProviderTokenTrait; -use App\Models\{Invoice,ProviderOauth,User}; +use App\Models\Invoice; class InvoiceAdd extends Command { - private const provider = 'intuit'; + use ProviderTokenTrait; /** * The name and signature of the console command. * * @var string */ - protected $signature = 'accounting:invoice:add' + protected $signature = 'intuit:invoice:add' .' {id : Invoice ID}' .' {user? : User Email}'; @@ -36,44 +37,46 @@ class InvoiceAdd extends Command */ public function handle() { - $uo = User::where('email',$this->argument('user') ?: config('osb.admin'))->singleOrFail(); + $to = $this->providerToken($this->argument('user')); - $so = ProviderOauth::where('name',self::provider)->singleOrFail(); - if (! ($to=$so->token($uo))) - abort(500,sprintf('Unknown Tokens for [%s]',$uo->email)); - - $o = Invoice::findOrFail($this->argument('id')); + $io = Invoice::findOrFail($this->argument('id')); // Check the customer exists - if ($o->account->providers->where('pivot.provider_oauth_id',$so->id)->count() !== 1) - throw new \Exception(sprintf('Account [%d] for Invoice [%d] not defined',$o->account_id,$o->id)); + if ($io->account->providers->where('pivot.provider_oauth_id',$to->provider->id)->count() !== 1) + throw new \Exception(sprintf('Account [%d] for Invoice [%d] not defined',$io->account_id,$io->id)); - $ao = $o->account->providers->where('pivot.provider_oauth_id',$so->id)->pop(); + $ao = $io->account->providers->where('pivot.provider_oauth_id',$to->provider->id)->pop(); // Some validation if (! $ao->pivot->ref) { - $this->error(sprintf('Accounting not defined for account [%d]',$o->account_id)); - exit(1); + $this->error(sprintf('Accounting not defined for account [%d]',$io->account_id)); + + return self::FAILURE; } $acc = new AccInvoice; $acc->CustomerRef = (object)['value'=>$ao->pivot->ref]; - $acc->DocNumber = $o->lid; - $acc->TxnDate = $o->created_at->format('Y-m-d'); - $acc->DueDate = $o->due_at->format('Y-m-d'); + $acc->DocNumber = $io->lid; + $acc->TxnDate = $io->created_at->format('Y-m-d'); + $acc->DueDate = $io->due_at->format('Y-m-d'); $lines = collect(); $c = 0; + $subtotal = 0; // @todo Group these by ItemRef and the Same Unit Price and Description, so that we can then use quantity to represent the number of them. - foreach ($o->items->groupBy(function($item) use ($so) { - return sprintf('%s.%s.%s.%s',$item->item_type_name,$item->price_base,$item->product->provider_ref($so),$item->taxes->pluck('description')->join('|')); - }) as $os) + foreach ($io->items->groupBy( + fn($item)=> + sprintf('%s.%s.%s.%s', + $item->item_type_name, + $item->price_base, + $item->product->provider_ref($to->provider), + $item->taxes->pluck('description')->join('|'))) as $os) { $key = $os->first(); // Some validation - if (! ($ref=$key->product->provider_ref($so))) { + if (! ($ref=$key->product->provider_ref($to->provider))) { $this->error(sprintf('Accounting not defined in product [%d]',$key->product_id)); return self::FAILURE; @@ -95,15 +98,35 @@ class InvoiceAdd extends Command 'UnitPrice' => $key->price_base, 'ItemRef' => ['value'=>$ref], // @todo It is assumed there is only 1 tax category - 'TaxCodeRef' => ['value'=>$key->taxes->first()->tax->provider_ref($so)], + 'TaxCodeRef' => ['value'=>$tcf=$key->taxes->first()->tax->provider_ref($to->provider)], ]; - $line->Amount = $os->sum('quantity')*$key->price_base; + $line->Amount = round($os->sum('quantity')*$key->price_base,2); + + $subtotal += $line->Amount; $lines->push($line); } $acc->Line = $lines; + // If our subtotal doesnt match, we need to add a tax line + if ($io->subtotal !== $subtotal) { + $acc->TxnTaxDetail = (object)[ + 'TotalTax' => $x=$io->total-$subtotal, + 'TaxLine' => [ + (object) [ + 'Amount' => $x, + 'DetailType' => 'TaxLineDetail', + 'TaxLineDetail' => (object)[ + // @todo It is assumed there is only 1 tax category + 'TaxRateRef' => (object)['value'=>$to->API()->getTaxCodeQuery($tcf)->getTaxRateRef()->first()], + 'NetAmountTaxable' => $io->subtotal, + ] + ] + ] + ]; + } + return AccountingInvoiceUpdate::dispatchSync($to,$acc); } } \ No newline at end of file