TDD for purchase order PDFs

This commit is contained in:
David Bomba 2022-06-06 22:27:17 +10:00
parent 04e55836ea
commit c0ba8aa822
18 changed files with 320 additions and 37 deletions

View File

@ -52,7 +52,10 @@ class InvoiceItemSum
$this->invoice = $invoice;
$this->currency = $this->invoice->client->currency();
if($this->invoice->vendor)
$this->currency = $this->invoice->vendor->currency();
else
$this->currency = $this->invoice->client->currency();
$this->line_items = [];
}

View File

@ -44,6 +44,8 @@ class InvoiceSum
private $gross_sub_total;
private $precision;
/**
* Constructs the object with Invoice and Settings object.
*
@ -53,8 +55,10 @@ class InvoiceSum
{
$this->invoice = $invoice;
// if(!$this->invoice->relationLoaded('client'))
// $this->invoice->load('client');
if($this->invoice->vendor)
$this->precision = $this->invoice->vendor->currency()->precision;
else
$this->precision = $this->invoice->client->currency()->precision;
$this->tax_map = new Collection;
}
@ -234,9 +238,9 @@ class InvoiceSum
public function getRecurringInvoice()
{
$this->invoice->amount = $this->formatValue($this->getTotal(), $this->invoice->client->currency()->precision);
$this->invoice->amount = $this->formatValue($this->getTotal(), $this->precision);
$this->invoice->total_taxes = $this->getTotalTaxes();
$this->invoice->balance = $this->formatValue($this->getTotal(), $this->invoice->client->currency()->precision);
$this->invoice->balance = $this->formatValue($this->getTotal(), $this->precision);
$this->invoice->saveQuietly();
@ -255,13 +259,13 @@ class InvoiceSum
if ($this->invoice->amount != $this->invoice->balance) {
$paid_to_date = $this->invoice->amount - $this->invoice->balance;
$this->invoice->balance = $this->formatValue($this->getTotal(), $this->invoice->client->currency()->precision) - $paid_to_date;
$this->invoice->balance = $this->formatValue($this->getTotal(), $this->precision) - $paid_to_date;
} else {
$this->invoice->balance = $this->formatValue($this->getTotal(), $this->invoice->client->currency()->precision);
$this->invoice->balance = $this->formatValue($this->getTotal(), $this->precision);
}
}
/* Set new calculated total */
$this->invoice->amount = $this->formatValue($this->getTotal(), $this->invoice->client->currency()->precision);
$this->invoice->amount = $this->formatValue($this->getTotal(), $this->precision);
$this->invoice->total_taxes = $this->getTotalTaxes();

View File

@ -73,7 +73,8 @@ class CreatePurchaseOrderPdf implements ShouldQueue
public function __construct($invitation, $disk = 'public')
{
$this->invitation = $invitation;
$this->company = $invitation->company;
$this->entity = $invitation->purchase_order;
$this->entity_string = 'purchase_order';

View File

@ -0,0 +1,42 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Models\Presenters;
/**
* Class VendorContactPresenter.
*/
class VendorContactPresenter extends EntityPresenter
{
/**
* @return string
*/
public function name()
{
$contact_name = $this->entity->first_name.' '.$this->entity->last_name;
if (strlen($contact_name) > 1) {
return $contact_name;
}
return $this->entity->vendor->present()->name();
}
public function first_name()
{
return $this->entity->first_name ?: '';
}
public function last_name()
{
return $this->entity->last_name ?: '';
}
}

View File

@ -12,7 +12,10 @@
namespace App\Models;
use App\Helpers\Invoice\InvoiceSum;
use App\Helpers\Invoice\InvoiceSumInclusive;
use App\Jobs\Entity\CreateEntityPdf;
use App\Jobs\Vendor\CreatePurchaseOrderPdf;
use App\Services\PurchaseOrder\PurchaseOrderService;
use App\Utils\Ninja;
use Illuminate\Database\Eloquent\SoftDeletes;
@ -165,14 +168,14 @@ class PurchaseOrder extends BaseModel
return Storage::disk(config('filesystems.default'))->{$type}($file_path);
}
elseif(Ninja::isHosted() && $portal){
$file_path = CreateEntityPdf::dispatchNow($invitation,config('filesystems.default'));
$file_path = CreatePurchaseOrderPdf::dispatchNow($invitation,config('filesystems.default'));
return Storage::disk(config('filesystems.default'))->{$type}($file_path);
}
if(Storage::disk('public')->exists($file_path))
return Storage::disk('public')->{$type}($file_path);
$file_path = CreateEntityPdf::dispatchNow($invitation);
$file_path = CreatePurchaseOrderPdf::dispatchNow($invitation);
return Storage::disk('public')->{$type}($file_path);
}
@ -193,7 +196,7 @@ class PurchaseOrder extends BaseModel
public function service()
{
return new PurchaseOrderService($this);
return new PurchaseOrderService($this);
}
public function invoices()
@ -211,4 +214,17 @@ class PurchaseOrder extends BaseModel
return $this->morphMany(Document::class, 'documentable');
}
public function calc()
{
$purchase_order_calc = null;
if ($this->uses_inclusive_taxes) {
$purchase_order_calc = new InvoiceSumInclusive($this);
} else {
$purchase_order_calc = new InvoiceSum($this);
}
return $purchase_order_calc->build();
}
}

View File

@ -15,9 +15,10 @@ use App\DataMapper\CompanySettings;
use App\Models\Presenters\VendorPresenter;
use App\Utils\Traits\AppSetup;
use App\Utils\Traits\GeneratesCounter;
use App\Utils\Traits\NumberFormatter;
use Illuminate\Database\Eloquent\SoftDeletes;
use Laracasts\Presenter\PresentableTrait;
use Illuminate\Support\Facades\Cache;
use Laracasts\Presenter\PresentableTrait;
class Vendor extends BaseModel
{
@ -26,7 +27,7 @@ class Vendor extends BaseModel
use GeneratesCounter;
use PresentableTrait;
use AppSetup;
protected $fillable = [
'name',
'assigned_user_id',
@ -166,6 +167,14 @@ class Vendor extends BaseModel
public function purchase_order_filepath($invitation)
{
$contact_key = $invitation->contact->contact_key;
return $this->company->company_key.'/'.$this->vendor_hash.'/'.$contact_key.'/purchase_orders/';
}
public function country()
{
return $this->belongsTo(Country::class);
}
}

View File

@ -11,6 +11,7 @@
namespace App\Models;
use App\Models\Presenters\VendorContactPresenter;
use App\Notifications\ClientContactResetPassword;
use App\Utils\Traits\MakesHash;
use Illuminate\Contracts\Translation\HasLocalePreference;
@ -35,6 +36,8 @@ class VendorContact extends Authenticatable implements HasLocalePreference
protected $touches = ['vendor'];
protected $presenter = VendorContactPresenter::class;
/* Allow microtime timestamps */
protected $dateFormat = 'Y-m-d H:i:s.u';

View File

@ -11,9 +11,10 @@
namespace App\Repositories;
use App\Factory\PurchaseOrderInvitationFactory;
use App\Models\PurchaseOrder;
use App\Models\PurchaseOrderInvitation;
use App\Models\VendorContact;
use App\Utils\Traits\MakesHash;
class PurchaseOrderRepository extends BaseRepository
@ -27,13 +28,83 @@ class PurchaseOrderRepository extends BaseRepository
public function save(array $data, PurchaseOrder $purchase_order) : ?PurchaseOrder
{
$purchase_order->fill($data);
$purchase_order->save();
if (isset($data['invitations'])) {
$invitations = collect($data['invitations']);
/* Get array of Keys which have been removed from the invitations array and soft delete each invitation */
$purchase_order->invitations->pluck('key')->diff($invitations->pluck('key'))->each(function ($invitation) {
$invitation = PurchaseOrderInvitation::where('key', $invitation)->first();
if ($invitation)
$invitation->delete();
});
foreach ($data['invitations'] as $invitation) {
//if no invitations are present - create one.
if (! $this->getInvitation($invitation)) {
if (isset($invitation['id']))
unset($invitation['id']);
//make sure we are creating an invite for a contact who belongs to the client only!
$contact = VendorContact::find($invitation['vendor_contact_id']);
if ($contact && $purchase_order->vendor_id == $contact->vendor_id) {
$new_invitation = PurchaseOrderInvitation::withTrashed()
->where('vendor_contact_id', $contact->id)
->where('purchase_order_id', $purchase_order->id)
->first();
if ($new_invitation && $new_invitation->trashed()) {
$new_invitation->restore();
} else {
$new_invitation = PurchaseOrderInvitationFactory::create($purchase_order->company_id, $purchase_order->user_id);
$new_invitation->purchase_order_id = $purchase_order->id;
$new_invitation->vendor_contact_id = $contact->id;
$new_invitation->key = $this->createDbHash($purchase_order->company->db);
$new_invitation->save();
}
}
}
}
}
/* If no invitations have been created, this is our fail safe to maintain state*/
if ($purchase_order->invitations()->count() == 0)
$purchase_order->service()->createInvitations();
nlog("4");
/* Recalculate invoice amounts */
$purchase_order = $purchase_order->calc()->getPurchaseOrder();
return $purchase_order;
}
public function getInvitationByKey($key) :?PurchaseOrderInvitation
{
return PurchaseOrderInvitation::where('key', $key)->first();
}
public function getInvitation($invitation, $resource=null)
{
if (is_array($invitation) && ! array_key_exists('key', $invitation))
return false;
$invitation = PurchaseOrderInvitation::where('key', $invitation['key'])->first();
return $invitation;
}
}

View File

@ -35,6 +35,9 @@ class Design extends BaseDesign
/** @var App\Models\Client */
public $client;
/** @var App\Models\Vendor */
public $vendor;
/** Global state of the design, @var array */
public $context;
@ -198,6 +201,9 @@ class Design extends BaseDesign
{
$elements = [];
if(!$this->vendor)
return $elements;
$variables = $this->context['pdf_variables']['vendor_details'];
foreach ($variables as $variable) {
@ -211,6 +217,9 @@ class Design extends BaseDesign
{
$elements = [];
if(!$this->client)
return $elements;
if ($this->type == self::DELIVERY_NOTE) {
$elements = [
['element' => 'p', 'content' => ctrans('texts.delivery_note'), 'properties' => ['data-ref' => 'delivery_note-label', 'style' => 'font-weight: bold; text-transform: uppercase']],

View File

@ -30,6 +30,10 @@ trait DesignHelpers
{
$this->syncPdfVariables();
if (isset($this->context['vendor'])) {
$this->vendor = $this->context['vendor'];
}
if (isset($this->context['client'])) {
$this->client = $this->context['client'];
}

View File

@ -39,10 +39,13 @@ class CreateInvitations extends AbstractService
$new_contact->is_primary = true;
$new_contact->save();
}
public function run()
{
$contacts = $this->purchase_order->vendor->contacts()->where('send_email', true)->get();
nlog("a");
if($contacts->count() == 0){
$this->createBlankContact();
@ -50,6 +53,9 @@ class CreateInvitations extends AbstractService
$contacts = $this->purchase_order->vendor->contacts;
}
nlog("b");
nlog($contacts->count());
$contacts->each(function ($contact) {
$invitation = PurchaseOrderInvitation::where('company_id', $this->purchase_order->company_id)
->where('vendor_contact_id', $contact->id)
@ -58,16 +64,24 @@ class CreateInvitations extends AbstractService
->first();
if (! $invitation) {
try{
$ii = PurchaseOrderInvitationFactory::create($this->purchase_order->company_id, $this->purchase_order->user_id);
$ii->key = $this->createDbHash($this->purchase_order->company->db);
$ii->purchase_order_id = $this->purchase_order->id;
$ii->vendor_contact_id = $contact->id;
$ii->save();
}
catch(\Exception $e){
nlog($e->getMessage());
}
} elseif (! $contact->send_email) {
$invitation->delete();
}
});
nlog("c");
if($this->purchase_order->invitations()->count() == 0) {
if($contacts->count() == 0){
@ -76,7 +90,7 @@ class CreateInvitations extends AbstractService
else{
$contact = $contacts->first();
$invitation = PurchaseOrder::where('company_id', $this->purchase_order->company_id)
$invitation = PurchaseOrderInvitation::where('company_id', $this->purchase_order->company_id)
->where('vendor_contact_id', $contact->id)
->where('purchase_order_id', $this->purchase_order->id)
->withTrashed()
@ -88,6 +102,9 @@ class CreateInvitations extends AbstractService
}
}
nlog("d");
$ii = PurchaseOrderInvitationFactory::create($this->purchase_order->company_id, $this->purchase_order->user_id);
$ii->key = $this->createDbHash($this->purchase_order->company->db);
$ii->purchase_order_id = $this->purchase_order->id;
@ -95,6 +112,7 @@ class CreateInvitations extends AbstractService
$ii->save();
}
nlog("e");
return $this->purchase_order;
}

View File

@ -0,0 +1,58 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2022. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://www.elastic.co/licensing/elastic-license
*/
namespace App\Services\PurchaseOrder;
use App\Jobs\Vendor\CreatePurchaseOrderPdf;
use App\Models\PurchaseOrder;
use App\Models\VendorContact;
use App\Services\AbstractService;
use App\Utils\TempFile;
use Illuminate\Support\Facades\Storage;
class GetPurchaseOrderPdf extends AbstractService
{
public function __construct(PurchaseOrder $purchase_order, VendorContact $contact = null)
{
$this->purchase_order = $purchase_order;
$this->contact = $contact;
}
public function run()
{
if (! $this->contact) {
$this->contact = $this->purchase_order->vendor->contacts()->where('send_email', true)->first();
}
$invitation = $this->purchase_order->invitations()->where('vendor_contact_id', $this->contact->id)->first();
if(!$invitation)
$invitation = $this->purchase_order->invitations()->first();
$path = $this->purchase_order->vendor->purchase_order_filepath($invitation);
$file_path = $path.$this->purchase_order->numberFormatter().'.pdf';
// $disk = 'public';
$disk = config('filesystems.default');
$file = Storage::disk($disk)->exists($file_path);
if (! $file) {
$file_path = CreatePurchaseOrderPdf::dispatchNow($invitation);
}
return $file_path;
}
}

View File

@ -15,6 +15,7 @@ namespace App\Services\PurchaseOrder;
use App\Models\PurchaseOrder;
use App\Services\PurchaseOrder\ApplyNumber;
use App\Services\PurchaseOrder\CreateInvitations;
use App\Services\PurchaseOrder\GetPurchaseOrderPdf;
use App\Utils\Traits\MakesHash;
class PurchaseOrderService
@ -23,7 +24,7 @@ class PurchaseOrderService
public PurchaseOrder $purchase_order;
public function __construct($purchase_order)
public function __construct(PurchaseOrder $purchase_order)
{
$this->purchase_order = $purchase_order;
}
@ -61,6 +62,11 @@ class PurchaseOrderService
return $this;
}
public function getPurchaseOrderPdf($contact = null)
{
return (new GetPurchaseOrderPdf($this->purchase_order, $contact))->run();
}
public function setStatus($status)
{
$this->purchase_order->status_id = $status;

View File

@ -52,7 +52,7 @@ class Helpers
*
* @return null|string
*/
public function formatCustomFieldValue($custom_fields, $field, $value, Client $client = null): ?string
public function formatCustomFieldValue($custom_fields, $field, $value, $entity = null): ?string
{
$custom_field = '';
@ -67,7 +67,7 @@ class Helpers
switch ($custom_field) {
case 'date':
return is_null($client) ? $value : $this->translateDate($value, $client->date_format(), $client->locale());
return is_null($entity) ? $value : $this->translateDate($value, $entity->date_format(), $entity->locale());
break;
case 'switch':

View File

@ -130,7 +130,8 @@ class VendorHtmlEngine
$data['$dueDate'] = &$data['$due_date'];
$data['$payment_due'] = ['value' => $this->translateDate($this->entity->due_date, $this->company->date_format(), $this->company->locale()) ?: '&nbsp;', 'label' => ctrans('texts.payment_due')];
$data['$poNumber'] = &$data['$invoice.po_number'];
$data['$poNumber'] = ['value' => $this->entity->po_number, 'label' => ctrans('texts.po_number')];
$data['$entity.datetime'] = ['value' => $this->formatDatetime($this->entity->created_at, $this->company->date_format(), $this->company->locale()), 'label' => ctrans('texts.date')];
$data['$payment_button'] = ['value' => '<a class="button" href="'.$this->invitation->getPaymentLink().'">'.ctrans('texts.pay_now').'</a>', 'label' => ctrans('texts.pay_now')];
@ -156,7 +157,7 @@ class VendorHtmlEngine
$data['$portal_url'] = ['value' => $this->invitation->getPortalLink(), 'label' =>''];
$data['$entity_number'] = &$data['$number'];
$data['$discount'] = &$data['$invoice.discount'];
$data['$discount'] = ['value' => $this->entity->discount, 'label' => ctrans('texts.discount')];
$data['$subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getSubTotal(), $this->vendor) ?: '&nbsp;', 'label' => ctrans('texts.subtotal')];
$data['$gross_subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getGrossSubTotal(), $this->vendor) ?: '&nbsp;', 'label' => ctrans('texts.subtotal')];
@ -165,8 +166,6 @@ class VendorHtmlEngine
else
$data['$net_subtotal'] = ['value' => Number::formatMoney($this->entity_calc->getSubTotal() - $this->entity_calc->getTotalDiscount(), $this->vendor) ?: '&nbsp;', 'label' => ctrans('texts.net_subtotal')];
$data['$invoice.subtotal'] = &$data['$subtotal'];
if ($this->entity->partial > 0) {
$data['$balance_due'] = ['value' => Number::formatMoney($this->entity->partial, $this->vendor) ?: '&nbsp;', 'label' => ctrans('texts.partial_due')];
$data['$balance_due_raw'] = ['value' => $this->entity->partial, 'label' => ctrans('texts.partial_due')];
@ -205,19 +204,19 @@ class VendorHtmlEngine
$data['$created_by_user'] = &$data['$user.name'];
$data['$assigned_to_user'] = ['value' => $this->entity->assigned_user ? $this->entity->assigned_user->present()->name() : '', 'label' => ctrans('texts.name')];
$data['$entity.public_notes'] = &$data['$invoice.public_notes'];
$data['$public_notes'] = &$data['$invoice.public_notes'];
$data['$public_notes'] = ['value' => $this->entity->public_notes, 'label' => ctrans("texts.public_notes")];
$data['$entity.public_notes'] = &$data['$public_notes'];
$data['$notes'] = &$data['$public_notes'];
$data['$purchase_order.custom1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'purchase_order1', $this->entity->custom_value1, $this->vendor) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'purchase_order1')];
$data['$purchase_order.custom2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'purchase_order2', $this->entity->custom_value2, $this->vendor) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'purchase_order2')];
$data['$purchase_order.custom3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'purchase_order3', $this->entity->custom_value3, $this->vendor) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'purchase_order3')];
$data['$purchase_order.custom4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'purchase_order4', $this->entity->custom_value4, $this->vendor) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'purchase_order4')];
$data['$purchase_order.custom1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'purchase_order1', $this->entity->custom_value1, $this->company) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'purchase_order1')];
$data['$purchase_order.custom2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'purchase_order2', $this->entity->custom_value2, $this->company) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'purchase_order2')];
$data['$purchase_order.custom3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'purchase_order3', $this->entity->custom_value3, $this->company) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'purchase_order3')];
$data['$purchase_order.custom4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'purchase_order4', $this->entity->custom_value4, $this->company) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'purchase_order4')];
$data['$vendor1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'vendor1', $this->vendor->custom_value1, $this->vendor) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'vendor1')];
$data['$vendor2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'vendor2', $this->vendor->custom_value2, $this->vendor) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'vendor2')];
$data['$vendor3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'vendor3', $this->vendor->custom_value3, $this->vendor) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'vendor3')];
$data['$vendor4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'vendor4', $this->vendor->custom_value4, $this->vendor) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'vendor4')];
$data['$vendor1'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'vendor1', $this->vendor->custom_value1, $this->company) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'vendor1')];
$data['$vendor2'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'vendor2', $this->vendor->custom_value2, $this->company) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'vendor2')];
$data['$vendor3'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'vendor3', $this->vendor->custom_value3, $this->company) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'vendor3')];
$data['$vendor4'] = ['value' => $this->helpers->formatCustomFieldValue($this->company->custom_fields, 'vendor4', $this->vendor->custom_value4, $this->company) ?: '&nbsp;', 'label' => $this->helpers->makeCustomField($this->company->custom_fields, 'vendor4')];
$data['$vendor.custom1'] = &$data['$vendor1'];
$data['$vendor.custom2'] = &$data['$vendor2'];
$data['$vendor.custom3'] = &$data['$vendor3'];
@ -430,6 +429,8 @@ class VendorHtmlEngine
$values = $this->buildEntityDataArray();
foreach ($values as $key => $value) {
nlog($key);
nlog($value);
$data['values'][$key] = $value['value'];
$data['labels'][$key.'_label'] = $value['label'];
}

View File

@ -1,5 +1,6 @@
<?php
use App\Models\Company;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
@ -15,10 +16,10 @@ class CreatePurchaseOrderInvitationsTable extends Migration
{
Schema::create('purchase_order_invitations', function (Blueprint $table) {
$table->id();
$table->unsignedInteger('company_id')->index();
$table->unsignedInteger('company_id');
$table->unsignedInteger('user_id');
$table->unsignedInteger('vendor_contact_id')->unique();
$table->unsignedBigInteger('purchase_order_id')->index()->unique();
$table->unsignedInteger('vendor_contact_id');
$table->unsignedBigInteger('purchase_order_id')->index();
$table->string('key')->index();
$table->string('transaction_reference')->nullable();
$table->string('message_id')->nullable()->index();
@ -37,6 +38,8 @@ class CreatePurchaseOrderInvitationsTable extends Migration
$table->timestamps(6);
$table->softDeletes('deleted_at', 6);
$table->unique(['vendor_contact_id', 'purchase_order_id'], 'vendor_purchase_unique');
$table->index(['deleted_at', 'purchase_order_id', 'company_id'], 'vendor_purchase_company_index');
});
@ -58,7 +61,8 @@ class CreatePurchaseOrderInvitationsTable extends Migration
$company->settings = $settings;
$company->save();
})
});
}
/**

View File

@ -40,6 +40,39 @@ class PurchaseOrderTest extends TestCase
}
public function testPostNewPurchaseOrderPdf()
{
$purchase_order = [
'status_id' => 1,
'discount' => 0,
'is_amount_discount' => 1,
'number' => '34343xx43',
'public_notes' => 'notes',
'is_deleted' => 0,
'custom_value1' => 0,
'custom_value2' => 0,
'custom_value3' => 0,
'custom_value4' => 0,
'status' => 1,
'vendor_id' => $this->encodePrimaryKey($this->vendor->id),
];
$response = $this->withHeaders([
'X-API-SECRET' => config('ninja.api_secret'),
'X-API-TOKEN' => $this->token,
])->post('/api/v1/purchase_orders/', $purchase_order)
->assertStatus(200);
$arr = $response->json();
$purchase_order = PurchaseOrder::find($this->decodePrimaryKey($arr['data']['id']));
$this->assertNotNull($purchase_order);
$purchase_order->service()->markSent()->getPurchaseOrderPdf();
}
public function testPurchaseOrderRest()
{
$response = $this->withHeaders([

View File

@ -294,6 +294,7 @@ trait MockAccountData
$this->vendor = Vendor::factory()->create([
'user_id' => $user_id,
'company_id' => $this->company->id,
'currency_id' => 1
]);