diff --git a/VERSION.txt b/VERSION.txt index 48a4fab6f338..96cf4cd38b12 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -5.5.88 \ No newline at end of file +5.5.89 \ No newline at end of file diff --git a/app/Services/Pdf/PdfMock.php b/app/Services/Pdf/PdfMock.php index 6766763bdc51..f1b18faa1273 100644 --- a/app/Services/Pdf/PdfMock.php +++ b/app/Services/Pdf/PdfMock.php @@ -11,19 +11,26 @@ namespace App\Services\Pdf; -use App\DataMapper\ClientSettings; +use App\Models\Quote; use App\Models\Client; +use App\Models\Credit; +use App\Models\Design; +use App\Models\Vendor; use App\Models\Company; use App\Models\Country; -use App\Models\Credit; -use App\Models\Currency; -use App\Models\Design; use App\Models\Invoice; -use App\Models\InvoiceInvitation; +use App\Models\Currency; use App\Models\PurchaseOrder; -use App\Models\Quote; -use App\Models\Vendor; +use App\Models\QuoteInvitation; use App\Utils\Traits\MakesHash; +use App\Models\CreditInvitation; +use App\Services\Pdf\PdfBuilder; +use App\Services\Pdf\PdfService; +use App\Models\InvoiceInvitation; +use App\Services\Pdf\PdfDesigner; +use App\DataMapper\ClientSettings; +use App\Services\Pdf\PdfConfiguration; +use App\Models\PurchaseOrderInvitation; class PdfMock { @@ -81,23 +88,46 @@ class PdfMock public function initEntity(): mixed { - match ($this->request['entity_type']) { - 'invoice' => $entity = Invoice::factory()->make(), - 'quote' => $entity = Quote::factory()->make(), - 'credit' => $entity = Credit::factory()->make(), - 'purchase_order' => $entity = PurchaseOrder::factory()->make(), - default => $entity = Invoice::factory()->make() - }; + $settings = new \stdClass; + $settings->entity = Client::class; + $settings->currency_id = '1'; + $settings->industry_id = ''; + $settings->size_id = ''; - if ($this->request['entity_type'] == PurchaseOrder::class) { - $entity->vendor = Vendor::factory()->make(); - } else { - $entity->client = Client::factory()->make(); + switch ($this->request['entity_type']) { + case 'invoice': + $entity = Invoice::factory()->make(); + $entity->client = Client::factory()->make(['settings' => $settings]); + $entity->invitation = InvoiceInvitation::factory()->make(); + break; + case 'quote': + $entity = Quote::factory()->make(); + $entity->client = Client::factory()->make(['settings' => $settings]); + $entity->invitation = QuoteInvitation::factory()->make(); + break; + case 'credit': + $entity = Credit::factory()->make(); + $entity->client = Client::factory()->make(['settings' => $settings]); + $entity->invitation = CreditInvitation::factory()->make(); + break; + case 'purchase_order': + $entity = PurchaseOrder::factory()->make(); + $entity->client = Client::factory()->make(['settings' => $settings]); + $entity->invitation = PurchaseOrderInvitation::factory()->make(); + break; + case PurchaseOrder::class: + $entity = PurchaseOrder::factory()->make(); + $entity->invitation = PurchaseOrderInvitation::factory()->make(); + $entity->vendor = Vendor::factory()->make(); + break; + default: + # code... + break; } + $entity->tax_map = $this->getTaxMap(); $entity->total_tax_map = $this->getTotalTaxMap(); - $entity->invitation = InvoiceInvitation::factory()->make(); $entity->invitation->company = $this->company; return $entity; @@ -182,7 +212,7 @@ class PdfMock '$client.public_notes' => ' ', '$company.postal_code' => $this->settings->postal_code, '$client.billing_city' => 'Aufderharchester', - '$secondary_font_name' => $this->settings->primary_font, + '$secondary_font_name' => isset($this->settings?->secondary_font) ? $this->settings->secondary_font : 'Roboto', '$product.line_total' => '', '$product.tax_amount' => '', '$company.vat_number' => $this->settings->vat_number, @@ -417,7 +447,7 @@ EPD '$country_2' => 'AF', '$firstName' => 'Benedict', '$user.name' => 'Derrick Monahan DDS Erna Wunsch', - '$font_name' => 'Roboto', + '$font_name' => $this->settings?->primary_font ?: 'Roboto', '$auto_bill' => 'This invoice will automatically be billed to your credit card on file on the due date.', '$payments' => '', '$task.tax' => '', diff --git a/config/ninja.php b/config/ninja.php index 5ebba959cfbe..7a9a27bf8681 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -14,8 +14,8 @@ return [ 'require_https' => env('REQUIRE_HTTPS', true), 'app_url' => rtrim(env('APP_URL', ''), '/'), 'app_domain' => env('APP_DOMAIN', 'invoicing.co'), - 'app_version' => '5.5.88', - 'app_tag' => '5.5.88', + 'app_version' => '5.5.89', + 'app_tag' => '5.5.89', 'minimum_client_version' => '5.0.16', 'terms_version' => '1.0.1', 'api_secret' => env('API_SECRET', ''), diff --git a/database/factories/QuoteFactory.php b/database/factories/QuoteFactory.php index c09da9d3e4bc..7b3ea5865afe 100644 --- a/database/factories/QuoteFactory.php +++ b/database/factories/QuoteFactory.php @@ -12,6 +12,7 @@ namespace Database\Factories; use App\Models\Quote; +use App\Factory\InvoiceItemFactory; use Illuminate\Database\Eloquent\Factories\Factory; class QuoteFactory extends Factory @@ -39,7 +40,7 @@ class QuoteFactory extends Factory // 'custom_value4' => $this->faker->numberBetween(1, 4), 'is_deleted' => false, 'po_number' => $this->faker->text(10), - 'line_items' => false, + 'line_items' => InvoiceItemFactory::generate(5), ]; } } diff --git a/database/factories/VendorFactory.php b/database/factories/VendorFactory.php index bfcec1759227..2eed73abda31 100644 --- a/database/factories/VendorFactory.php +++ b/database/factories/VendorFactory.php @@ -40,7 +40,7 @@ class VendorFactory extends Factory 'postal_code' => $this->faker->postcode(), 'country_id' => 4, 'vendor_hash' => Str::random(40), - + 'currency_id' => 1, ]; } } diff --git a/openapi/api-docs.yaml b/openapi/api-docs.yaml index 7e8fb1f123f0..92111a435447 100644 --- a/openapi/api-docs.yaml +++ b/openapi/api-docs.yaml @@ -12054,7 +12054,7 @@ paths: /api/v1/recurring_invoices: get: tags: - - recurring_invoices + - Recurring Invoices summary: "List recurring invoices" description: | Lists invoices with the option to chain multiple query parameters allowing fine grained filtering of the list. @@ -12125,7 +12125,7 @@ paths: $ref: "#/components/responses/default" post: tags: - - recurring_invoices + - Recurring Invoices summary: "Create recurring invoice" description: "Adds a Recurring Invoice to the system" operationId: storeRecurringInvoice @@ -12159,7 +12159,7 @@ paths: "/api/v1/recurring_invoices/{id}": get: tags: - - recurring_invoices + - Recurring Invoices summary: "Show recurring invoice" description: "Displays an RecurringInvoice by id" operationId: showRecurringInvoice @@ -12199,7 +12199,7 @@ paths: $ref: "#/components/responses/default" put: tags: - - recurring_invoices + - Recurring Invoices summary: "Update recurring invoice" description: "Handles the updating of an RecurringInvoice by id" operationId: updateRecurringInvoice @@ -12239,7 +12239,7 @@ paths: $ref: "#/components/responses/default" delete: tags: - - recurring_invoices + - Recurring Invoices summary: "Delete recurring invoice" description: "Handles the deletion of an RecurringInvoice by id" operationId: deleteRecurringInvoice @@ -12276,7 +12276,7 @@ paths: "/api/v1/recurring_invoices/{id}/edit": get: tags: - - recurring_invoices + - Recurring Invoices summary: "Edit recurring invoice" description: "Displays an RecurringInvoice by id" operationId: editRecurringInvoice @@ -12318,7 +12318,7 @@ paths: /api/v1/recurring_invoices/create: get: tags: - - recurring_invoices + - Recurring Invoices summary: "Blank recurring invoice" description: "Returns a blank object with default values" operationId: getRecurringInvoicesCreate @@ -12351,25 +12351,52 @@ paths: /api/v1/recurring_invoices/bulk: post: tags: - - recurring_invoices + - Recurring Invoices summary: "Bulk recurring invoice actions" - description: "" + description: | + There are multiple actions that are available including: + operationId: bulkRecurringInvoices parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/index" requestBody: - description: "Hashed IDs" + description: "Bulk action details" required: true content: application/json: schema: - type: array - items: - description: "Array of hashed IDs to be bulk 'actioned" - type: integer - example: "[0,1,2,3]" + type: object + properties: + action: + type: string + description: | + The action to be performed, options include: + - `start` + Starts (or restarts) the recurring invoice. **note** if the recurring invoice has been stopped for a long time, it will attempt to catch back up firing a new Invoice every hour per interval that has been missed. + If you do not wish to have the recurring invoice catch up, you should set the next_send_date to the correct date you wish the recurring invoice to commence from. + - `stop` + Stops the recurring invoice. + - `send_now` + Force sends the recurring invoice - this option is only available when the recurring invoice is in a draft state. + - `restore` + Restores the recurring invoice from an archived or deleted state. + - `archive` + Archives the recurring invoice. The recurring invoice will not fire in this state. + - `delete` + Deletes a recurring invoice. + + required: true + ids: + required: true + type: array + items: + description: "Array of hashed IDs to be bulk 'actioned - ['D2J234DFA','D2J234DFA','D2J234DFA']" + type: string + example: + action: start + ids: "['D2J234DFA','D2J234DFA','D2J234DFA']" responses: 200: description: "The RecurringInvoice response" @@ -12396,7 +12423,7 @@ paths: get: deprecated: true tags: - - recurring_invoices + - Recurring Invoices summary: "Custom recurring invoice action" description: "Performs a custom action on an RecurringInvoice.\n\n The current range of actions are as follows\n - clone_to_RecurringInvoice\n - clone_to_quote\n - history\n - delivery_note\n - mark_paid\n - download\n - archive\n - delete\n - email" operationId: actionRecurringInvoice @@ -12445,7 +12472,7 @@ paths: "/api/v1/recurring_invoice/{invitation_key}/download": get: tags: - - recurring_invoices + - Recurring Invoices summary: "Download recurring invoice PDF" description: "Downloads a specific invoice" operationId: downloadRecurringInvoice @@ -12482,7 +12509,7 @@ paths: "/api/v1/recurring_invoices/{id}/upload": put: tags: - - recurring_invoices + - Recurring Invoices summary: "Add recurring invoice document" description: "Handles the uploading of a document to a recurring_invoice" operationId: uploadRecurringInvoice @@ -17296,7 +17323,7 @@ tags: - name: invoices description: | Endpoint definitions for interacting with invoices. - - name: recurring_invoices + - name: Recurring Invoices description: | Endpoint definitions for interacting with recurring_invoices. - name: payments diff --git a/openapi/misc/misc.yaml b/openapi/misc/misc.yaml index 37ac872de72e..163204ca13f3 100644 --- a/openapi/misc/misc.yaml +++ b/openapi/misc/misc.yaml @@ -14,7 +14,7 @@ tags: - name: invoices description: | Endpoint definitions for interacting with invoices. - - name: recurring_invoices + - name: Recurring Invoices description: | Endpoint definitions for interacting with recurring_invoices. - name: payments diff --git a/openapi/paths/recurring_invoices.yaml b/openapi/paths/recurring_invoices.yaml index 0ca64642c0e2..bb3a30f28fab 100644 --- a/openapi/paths/recurring_invoices.yaml +++ b/openapi/paths/recurring_invoices.yaml @@ -1,7 +1,7 @@ /api/v1/recurring_invoices: get: tags: - - recurring_invoices + - Recurring Invoices summary: "List recurring invoices" description: | Lists invoices with the option to chain multiple query parameters allowing fine grained filtering of the list. @@ -72,7 +72,7 @@ $ref: "#/components/responses/default" post: tags: - - recurring_invoices + - Recurring Invoices summary: "Create recurring invoice" description: "Adds a Recurring Invoice to the system" operationId: storeRecurringInvoice @@ -106,7 +106,7 @@ "/api/v1/recurring_invoices/{id}": get: tags: - - recurring_invoices + - Recurring Invoices summary: "Show recurring invoice" description: "Displays an RecurringInvoice by id" operationId: showRecurringInvoice @@ -146,7 +146,7 @@ $ref: "#/components/responses/default" put: tags: - - recurring_invoices + - Recurring Invoices summary: "Update recurring invoice" description: "Handles the updating of an RecurringInvoice by id" operationId: updateRecurringInvoice @@ -186,7 +186,7 @@ $ref: "#/components/responses/default" delete: tags: - - recurring_invoices + - Recurring Invoices summary: "Delete recurring invoice" description: "Handles the deletion of an RecurringInvoice by id" operationId: deleteRecurringInvoice @@ -223,7 +223,7 @@ "/api/v1/recurring_invoices/{id}/edit": get: tags: - - recurring_invoices + - Recurring Invoices summary: "Edit recurring invoice" description: "Displays an RecurringInvoice by id" operationId: editRecurringInvoice @@ -265,7 +265,7 @@ /api/v1/recurring_invoices/create: get: tags: - - recurring_invoices + - Recurring Invoices summary: "Blank recurring invoice" description: "Returns a blank object with default values" operationId: getRecurringInvoicesCreate @@ -298,25 +298,52 @@ /api/v1/recurring_invoices/bulk: post: tags: - - recurring_invoices + - Recurring Invoices summary: "Bulk recurring invoice actions" - description: "" + description: | + There are multiple actions that are available including: + operationId: bulkRecurringInvoices parameters: - $ref: "#/components/parameters/X-API-TOKEN" - $ref: "#/components/parameters/X-Requested-With" - $ref: "#/components/parameters/index" requestBody: - description: "Hashed IDs" + description: "Bulk action details" required: true content: application/json: schema: - type: array - items: - description: "Array of hashed IDs to be bulk 'actioned" - type: integer - example: "[0,1,2,3]" + type: object + properties: + action: + type: string + description: | + The action to be performed, options include: + - `start` + Starts (or restarts) the recurring invoice. **note** if the recurring invoice has been stopped for a long time, it will attempt to catch back up firing a new Invoice every hour per interval that has been missed. + If you do not wish to have the recurring invoice catch up, you should set the next_send_date to the correct date you wish the recurring invoice to commence from. + - `stop` + Stops the recurring invoice. + - `send_now` + Force sends the recurring invoice - this option is only available when the recurring invoice is in a draft state. + - `restore` + Restores the recurring invoice from an archived or deleted state. + - `archive` + Archives the recurring invoice. The recurring invoice will not fire in this state. + - `delete` + Deletes a recurring invoice. + + required: true + ids: + required: true + type: array + items: + description: "Array of hashed IDs to be bulk 'actioned - ['D2J234DFA','D2J234DFA','D2J234DFA']" + type: string + example: + action: start + ids: "['D2J234DFA','D2J234DFA','D2J234DFA']" responses: 200: description: "The RecurringInvoice response" @@ -343,7 +370,7 @@ get: deprecated: true tags: - - recurring_invoices + - Recurring Invoices summary: "Custom recurring invoice action" description: "Performs a custom action on an RecurringInvoice.\n\n The current range of actions are as follows\n - clone_to_RecurringInvoice\n - clone_to_quote\n - history\n - delivery_note\n - mark_paid\n - download\n - archive\n - delete\n - email" operationId: actionRecurringInvoice @@ -392,7 +419,7 @@ "/api/v1/recurring_invoice/{invitation_key}/download": get: tags: - - recurring_invoices + - Recurring Invoices summary: "Download recurring invoice PDF" description: "Downloads a specific invoice" operationId: downloadRecurringInvoice @@ -429,7 +456,7 @@ "/api/v1/recurring_invoices/{id}/upload": put: tags: - - recurring_invoices + - Recurring Invoices summary: "Add recurring invoice document" description: "Handles the uploading of a document to a recurring_invoice" operationId: uploadRecurringInvoice