diff --git a/app/Designs/Creative.php b/app/Designs/Creative.php index 83594d7fe148..9e16a0d378c8 100644 --- a/app/Designs/Creative.php +++ b/app/Designs/Creative.php @@ -98,7 +98,7 @@ class Creative extends AbstractDesign $table_body - $entity.public_notes + $entity.public_notes $total_tax_labels $line_tax_labels diff --git a/app/Factory/InvoiceItemFactory.php b/app/Factory/InvoiceItemFactory.php index 5c528f27ed1d..edf3e19f8d05 100644 --- a/app/Factory/InvoiceItemFactory.php +++ b/app/Factory/InvoiceItemFactory.php @@ -61,7 +61,7 @@ class InvoiceItemFactory $item->line_total = $item->quantity * $item->cost; $item->is_amount_discount = true; $item->discount = $faker->numberBetween(1, 10); - $item->notes = $faker->realText(20); + $item->notes = $faker->realText(50); $item->product_key = $faker->word(); $item->custom_value1 = $faker->realText(10); $item->custom_value2 = $faker->realText(10); diff --git a/app/Http/Controllers/OpenAPI/ClientGatewayToken.php b/app/Http/Controllers/OpenAPI/ClientGatewayToken.php index e2e9694fc56f..b16740d89616 100644 --- a/app/Http/Controllers/OpenAPI/ClientGatewayToken.php +++ b/app/Http/Controllers/OpenAPI/ClientGatewayToken.php @@ -7,7 +7,9 @@ * @OA\Property(property="company_id", type="string", example="2", description="______"), * @OA\Property(property="client_id", type="string", example="2", description="______"), * @OA\Property(property="token", type="string", example="2", description="______"), + * @OA\Property(property="routing_number", type="string", example="2", description="______"), * @OA\Property(property="company_gateway_id", type="string", example="2", description="______"), * @OA\Property(property="is_default", type="boolean", example="true", description="______"), + * * ) */ diff --git a/app/Jobs/Util/Import.php b/app/Jobs/Util/Import.php index 4658a6c05956..860362a10280 100644 --- a/app/Jobs/Util/Import.php +++ b/app/Jobs/Util/Import.php @@ -143,6 +143,7 @@ class Import implements ShouldQueue $validator = Validator::make($data, $rules); if ($validator->fails()) { + \Log::error($validator->errors()); throw new MigrationValidatorFailed($validator->errors()); } @@ -443,12 +444,12 @@ class Import implements ShouldQueue ); $old_user_key = array_key_exists('user_id', $resource) ?? $this->user->id; + + $key = "invoices_{$resource['id']}"; - $this->ids['quotes'] = [ - "quotes_{$old_user_key}" => [ - 'old' => $old_user_key, - 'new' => $invoice->id, - ] + $this->ids['quotes'][$key] = [ + 'old' => $resource['id'], + 'new' => $invoice->id, ]; } @@ -517,10 +518,12 @@ class Import implements ShouldQueue $modified = $resource; if (array_key_exists('invoice_id', $resource) && !array_key_exists('invoices', $this->ids)) { + \Log::error("ivoice id missing"); throw new ResourceDependencyMissing(array_key_first($data), 'invoices'); } if (array_key_exists('expense_id', $resource) && !array_key_exists('expenses', $this->ids)) { + \Log::error("expense id missing"); throw new ResourceDependencyMissing(array_key_first($data), 'expenses'); } @@ -534,21 +537,21 @@ class Import implements ShouldQueue } if(array_key_exists('expense_id', $resource) && $resource['expense_id']) { - $modified['documentable_id'] = $this->transformId('expense', $resource['expense_id']); + $modified['documentable_id'] = $this->transformId('expenses', $resource['expense_id']); $modified['documentable_type'] = 'App\\Models\\Expense'; } $modified['user_id'] = $this->processUserId($resource); $modified['company_id'] = $this->company->id; - $payment = Document::create($modified); + $document = Document::create($modified); $old_user_key = array_key_exists('user_id', $resource) ?? $this->user->id; - $this->ids['payments'] = [ - "payments_{$old_user_key}" => [ + $this->ids['documents'] = [ + "documents_{$old_user_key}" => [ 'old' => $old_user_key, - 'new' => $payment->id, + 'new' => $document->id, ] ]; } diff --git a/app/Models/Payment.php b/app/Models/Payment.php index 3873f843fe97..5488269dc281 100644 --- a/app/Models/Payment.php +++ b/app/Models/Payment.php @@ -18,6 +18,7 @@ use App\Models\DateFormat; use App\Models\Filterable; use App\Models\Paymentable; use App\Services\Ledger\LedgerService; +use App\Services\Payment\PaymentService; use App\Utils\Number; use App\Utils\Traits\MakesDates; use App\Utils\Traits\MakesHash; @@ -175,6 +176,11 @@ class Payment extends BaseModel return new LedgerService($this); } + public function service() + { + return new PaymentService($this); + } + public function resolveRouteBinding($value) { return $this diff --git a/app/PaymentDrivers/StripePaymentDriver.php b/app/PaymentDrivers/StripePaymentDriver.php index ae09a938f688..80ecda1d31c9 100644 --- a/app/PaymentDrivers/StripePaymentDriver.php +++ b/app/PaymentDrivers/StripePaymentDriver.php @@ -178,7 +178,7 @@ class StripePaymentDriver extends BasePaymentDriver $payment_meta->exp_year = $stripe_payment_method_obj['card']['exp_year']; $payment_meta->brand = $stripe_payment_method_obj['card']['brand']; $payment_meta->last4 = $stripe_payment_method_obj['card']['last4']; - $payment_meta->type = $stripe_payment_method_obj['type']; + $payment_meta->type = GatewayType::CREDIT_CARD; } $cgt = new ClientGatewayToken; diff --git a/app/Services/Credit/CreditService.php b/app/Services/Credit/CreditService.php index 5a3a2a6ccc6e..943526b9cd4b 100644 --- a/app/Services/Credit/CreditService.php +++ b/app/Services/Credit/CreditService.php @@ -5,13 +5,12 @@ use App\Credit; class CreditService { + protected $credit; - public function __construct($credit) { $this->credit = $credit; - } public function getCreditPdf($contact) @@ -44,6 +43,7 @@ class CreditService public function save() : ?Credit { $this->credit->save(); + return $this->credit; } } diff --git a/app/Services/Payment/UpdateInvoicePayment.php b/app/Services/Payment/UpdateInvoicePayment.php index b4563bc9b146..b437d93b07b4 100644 --- a/app/Services/Payment/UpdateInvoicePayment.php +++ b/app/Services/Payment/UpdateInvoicePayment.php @@ -29,7 +29,7 @@ class UpdateInvoicePayment $this->payment ->ledger() - ->updatePaymentBalance($this->payment, ($invoice->balance*-1)); + ->updatePaymentBalance($invoice->balance*-1); $this->payment->client ->service() @@ -66,7 +66,7 @@ class UpdateInvoicePayment $this->payment ->ledger() - ->updatePaymentBalance($this->payment, ($invoice->partial*-1)); + ->updatePaymentBalance($invoice->partial*-1); $this->payment->client->service() ->updateBalance($invoice->partial*-1) @@ -85,7 +85,7 @@ class UpdateInvoicePayment $this->payment ->ledger() - ->updatePaymentBalance($this->payment, ($invoice->balance*-1)); + ->updatePaymentBalance($invoice->balance*-1); $this->payment->client->service() ->updateBalance($invoice->balance*-1) diff --git a/database/migrations/2014_10_13_000000_create_users_table.php b/database/migrations/2014_10_13_000000_create_users_table.php index 728daa8d246e..160b790598aa 100644 --- a/database/migrations/2014_10_13_000000_create_users_table.php +++ b/database/migrations/2014_10_13_000000_create_users_table.php @@ -1128,6 +1128,7 @@ class CreateUsersTable extends Migration $table->unsignedInteger('company_id'); $table->unsignedInteger('client_id')->nullable(); $table->text('token')->nullable(); + $table->text('routing_number')->nullable(); $table->unsignedInteger('company_gateway_id'); $table->string('gateway_customer_reference')->nullable(); $table->unsignedInteger('gateway_type_id'); diff --git a/database/seeds/RandomDataSeeder.php b/database/seeds/RandomDataSeeder.php index c964ca101805..6631c44936cd 100644 --- a/database/seeds/RandomDataSeeder.php +++ b/database/seeds/RandomDataSeeder.php @@ -8,8 +8,6 @@ use App\Events\Invoice\InvoiceWasUpdated; use App\Events\Payment\PaymentWasCreated; use App\Helpers\Invoice\InvoiceSum; use App\Helpers\Invoice\InvoiceSumInclusive; -use App\Jobs\Company\UpdateCompanyLedgerWithInvoice; -//use App\Jobs\Invoice\UpdateInvoicePayment; use App\Listeners\Credit\CreateCreditInvitation; use App\Listeners\Invoice\CreateInvoiceInvitation; use App\Models\Account; @@ -165,7 +163,7 @@ class RandomDataSeeder extends Seeder event(new CreateInvoiceInvitation($invoice)); - UpdateCompanyLedgerWithInvoice::dispatchNow($invoice, $invoice->balance, $invoice->company); + $invoice->ledger()->updateInvoiceBalance($invoice->balance); $invoice->service()->markSent()->save(); @@ -187,7 +185,7 @@ class RandomDataSeeder extends Seeder event(new PaymentWasCreated($payment, $payment->company)); - $payment->service()->UpdateInvoicePayment(); + $payment->service()->updateInvoicePayment(); // UpdateInvoicePayment::dispatchNow($payment, $payment->company); } diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index effb37c378e2..000000000000 --- a/jest.config.js +++ /dev/null @@ -1,17 +0,0 @@ -module.exports = { - "roots": [ - "resources/js/src" - ], - "transform": { - "^.+\\.tsx?$": "ts-jest" - }, - "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "jsx", - "json", - "node" - ], -} \ No newline at end of file diff --git a/resources/assets/js/vendor/I18n.js b/resources/assets/js/vendor/I18n.js deleted file mode 100644 index eaf63680e133..000000000000 --- a/resources/assets/js/vendor/I18n.js +++ /dev/null @@ -1,106 +0,0 @@ -export default class I18n -{ - /** - * Initialize a new translation instance. - * - * @param {string} key - * @return {void} - */ - constructor(key = 'translations') - { - this.key = key; - } - - /** - * Get and replace the string of the given key. - * - * @param {string} key - * @param {object} replace - * @return {string} - */ - trans(key, replace = {}) - { - return this._replace(this._extract(key), replace); - } - - /** - * Get and pluralize the strings of the given key. - * - * @param {string} key - * @param {number} count - * @param {object} replace - * @return {string} - */ - trans_choice(key, count = 1, replace = {}) - { - let translations = this._extract(key, '|').split('|'), translation; - - translations.some(t => translation = this._match(t, count)); - - translation = translation || (count > 1 ? translations[1] : translations[0]); - - return this._replace(translation, replace); - } - - /** - * Match the translation limit with the count. - * - * @param {string} translation - * @param {number} count - * @return {string|null} - */ - _match(translation, count) - { - let match = translation.match(/^[\{\[]([^\[\]\{\}]*)[\}\]](.*)/); - - if (! match) return; - - if (match[1].includes(',')) { - let [from, to] = match[1].split(','); - - if (to === '*' && count >= from) { - return match[2]; - } else if (from === '*' && count <= to) { - return match[2]; - } else if (count >= from && count <= to) { - return match[2]; - } - } - - return match[1] == count ? match[2] : null; - } - - /** - * Replace the placeholders. - * - * @param {string} translation - * @param {object} replace - * @return {string} - */ - _replace(translation, replace) - { - for (let placeholder in replace) { - translation = translation - .replace(`:${placeholder}`, replace[placeholder]) - .replace(`:${placeholder.toUpperCase()}`, replace[placeholder].toUpperCase()) - .replace( - `:${placeholder.charAt(0).toUpperCase()}${placeholder.slice(1)}`, - replace[placeholder].charAt(0).toUpperCase()+replace[placeholder].slice(1) - ); - } - - return translation.trim(); - } - - /** - * The extract helper. - * - * @param {string} key - * @param {mixed} value - * @return {mixed} - */ - _extract(key, value = null) - { - return key.toString().split('.').reduce((t, i) => t[i] || (value || key), window[this.key]); - } -} diff --git a/resources/assets/js/vue-i18n-locales.generated.js b/resources/assets/js/vue-i18n-locales.generated.js deleted file mode 100644 index 79b926a2a5ea..000000000000 --- a/resources/assets/js/vue-i18n-locales.generated.js +++ /dev/null @@ -1,81762 +0,0 @@ -export default { - "ca": { - "passwords": { - "password": "Les contrasenyes han de contenir almenys 6 caràcters i coincidir.", - "reset": "La contrasenya s'ha restablert!", - "sent": "Recordatori de contrasenya enviat!", - "token": "Aquest token de recuperació de contrasenya és invàlid.", - "user": "No podem trobar a un usuari amb aquest correu electrònic." - }, - "auth": { - "failed": "Aquestes credencials no concorden amb els nostres registres.", - "throttle": "Heu superat el nombre màxim d'intents d'accés. Per favor, torna a intentar-ho en {seconds} segons." - }, - "pagination": { - "previous": "« Anterior", - "next": "Següent »" - }, - "validation": { - "accepted": "{attribute} ha de ser acceptat.", - "active_url": "{attribute} no és un URL vàlid.", - "after": "{attribute} ha de ser una data posterior a {date}.", - "alpha": "{attribute} només pot contenir lletres.", - "alpha_dash": "{attribute} només por contenir lletres, números i guions.", - "alpha_num": "{attribute} només pot contenir lletres i números.", - "array": "{attribute} ha de ser un conjunt.", - "before": "{attribute} ha de ser una data anterior a {date}.", - "between": { - "numeric": "{attribute} ha d'estar entre {min} - {max}.", - "file": "{attribute} ha de pesar entre {min} - {max} kilobytes.", - "string": "{attribute} ha de tenir entre {min} - {max} caràcters.", - "array": "{attribute} ha de tenir entre {min} - {max} ítems." - }, - "boolean": "El camp {attribute} ha de ser veritat o fals", - "confirmed": "La confirmació de {attribute} no coincideix.", - "date": "{attribute} no és una data vàlida.", - "date_format": "{attribute} no correspon al format {format}.", - "different": "{attribute} i {other} han de ser diferents.", - "digits": "{attribute} ha de tenir {digits} digits.", - "digits_between": "{attribute} ha de tenir entre {min} i {max} digits.", - "dimensions": "The {attribute} has invalid image dimensions.", - "distinct": "The {attribute} field has a duplicate value.", - "email": "{attribute} no és un e-mail vàlid", - "exists": "{attribute} és invàlid.", - "filled": "El camp {attribute} és obligatori.", - "image": "{attribute} ha de ser una imatge.", - "in": "{attribute} és invàlid", - "in_array": "The {attribute} field does not exist in {other}.", - "integer": "{attribute} ha de ser un nombre enter.", - "ip": "{attribute} ha de ser una adreça IP vàlida.", - "json": "El camp {attribute} ha de contenir una cadena JSON vàlida.", - "max": { - "numeric": "{attribute} no ha de ser major a {max}.", - "file": "{attribute} no ha de ser més gran que {max} kilobytes.", - "string": "{attribute} no ha de ser més gran que {max} characters.", - "array": "{attribute} no ha de tenir més de {max} ítems." - }, - "mimes": "{attribute} ha de ser un arxiu amb format: {values}.", - "min": { - "numeric": "El tamany de {attribute} ha de ser d'almenys {min}.", - "file": "El tamany de {attribute} ha de ser d'almenys {min} kilobytes.", - "string": "{attribute} ha de contenir almenys {min} caràcters.", - "array": "{attribute} ha de tenir almenys {min} ítems." - }, - "not_in": "{attribute} és invàlid.", - "numeric": "{attribute} ha de ser numèric.", - "present": "The {attribute} field must be present.", - "regex": "El format de {attribute} és invàlid.", - "required": "El camp {attribute} és obligatori.", - "required_if": "El camp {attribute} és obligatori quan {other} és {value}.", - "required_unless": "The {attribute} field is required unless {other} is in {values}.", - "required_with": "El camp {attribute} és obligatori quan {values} és present.", - "required_with_all": "El camp {attribute} és obligatori quan {values} és present.", - "required_without": "El camp {attribute} és obligatori quan {values} no és present.", - "required_without_all": "El camp {attribute} és obligatori quan cap dels {values} estan presents.", - "same": "{attribute} i {other} han de coincidir.", - "size": { - "numeric": "El tamany de {attribute} ha de ser {size}.", - "file": "El tamany de {attribute} ha de ser {size} kilobytes.", - "string": "{attribute} ha de contenir {size} caràcters.", - "array": "{attribute} ha de contenir {size} ítems." - }, - "string": "El camp {attribute} ha de ser una cadena de caràcters.", - "timezone": "El camp {attribute} ha de ser una zona vàlida.", - "unique": "{attribute} ja ha estat registrat.", - "url": "El format {attribute} és invàlid.", - "custom": { - "attribute-name": { - "rule-name": "custom-message" - } - }, - "attributes": [] - }, - "texts": { - "organization": "Organization", - "name": "Name", - "website": "Website", - "work_phone": "Phone", - "address": "Address", - "address1": "Street", - "address2": "Apt\/Suite", - "city": "City", - "state": "State\/Province", - "postal_code": "Postal Code", - "country_id": "Country", - "contacts": "Contacts", - "first_name": "First Name", - "last_name": "Last Name", - "phone": "Phone", - "email": "Email", - "additional_info": "Additional Info", - "payment_terms": "Payment Terms", - "currency_id": "Currency", - "size_id": "Company Size", - "industry_id": "Industry", - "private_notes": "Private Notes", - "invoice": "Invoice", - "client": "Client", - "invoice_date": "Invoice Date", - "due_date": "Due Date", - "invoice_number": "Invoice Number", - "invoice_number_short": "Invoice #", - "po_number": "PO Number", - "po_number_short": "PO #", - "frequency_id": "How Often", - "discount": "Discount", - "taxes": "Taxes", - "tax": "Tax", - "item": "Item", - "description": "Description", - "unit_cost": "Unit Cost", - "quantity": "Quantity", - "line_total": "Line Total", - "subtotal": "Subtotal", - "paid_to_date": "Paid to Date", - "balance_due": "Balance Due", - "invoice_design_id": "Design", - "terms": "Terms", - "your_invoice": "Your Invoice", - "remove_contact": "Remove contact", - "add_contact": "Add contact", - "create_new_client": "Create new client", - "edit_client_details": "Edit client details", - "enable": "Enable", - "learn_more": "Learn more", - "manage_rates": "Manage rates", - "note_to_client": "Note to Client", - "invoice_terms": "Invoice Terms", - "save_as_default_terms": "Save as default terms", - "download_pdf": "Download PDF", - "pay_now": "Pay Now", - "save_invoice": "Save Invoice", - "clone_invoice": "Clone To Invoice", - "archive_invoice": "Archive Invoice", - "delete_invoice": "Delete Invoice", - "email_invoice": "Email Invoice", - "enter_payment": "Enter Payment", - "tax_rates": "Tax Rates", - "rate": "Rate", - "settings": "Settings", - "enable_invoice_tax": "Enable specifying an invoice tax<\/b>", - "enable_line_item_tax": "Enable specifying line item taxes<\/b>", - "dashboard": "Dashboard", - "clients": "Clients", - "invoices": "Invoices", - "payments": "Payments", - "credits": "Credits", - "history": "History", - "search": "Search", - "sign_up": "Sign Up", - "guest": "Guest", - "company_details": "Company Details", - "online_payments": "Online Payments", - "notifications": "Notifications", - "import_export": "Import | Export", - "done": "Done", - "save": "Save", - "create": "Create", - "upload": "Upload", - "import": "Import", - "download": "Download", - "cancel": "Cancel", - "close": "Close", - "provide_email": "Please provide a valid email address", - "powered_by": "Powered by", - "no_items": "No items", - "recurring_invoices": "Recurring Invoices", - "recurring_help": "

Automatically send clients the same invoices weekly, bi-monthly, monthly, quarterly or annually. <\/p>\n

Use {MONTH}, {QUARTER} or {YEAR} for dynamic dates. Basic math works as well, for example {MONTH}-1.<\/p>\n

Examples of dynamic invoice variables:<\/p>\n