diff --git a/app/BulkActions/Purchases/Bills.php b/app/BulkActions/Purchases/Bills.php index 8d65a3277..c48e94d74 100644 --- a/app/BulkActions/Purchases/Bills.php +++ b/app/BulkActions/Purchases/Bills.php @@ -5,7 +5,7 @@ namespace App\BulkActions\Purchases; use App\Abstracts\BulkAction; use App\Events\Document\DocumentCancelled; use App\Events\Document\DocumentReceived; -use App\Exports\Purchases\Bills as Export; +use App\Exports\Purchases\Bills\Bills as Export; use App\Jobs\Banking\CreateBankingDocumentTransaction; use App\Jobs\Document\CreateDocumentHistory; use App\Jobs\Document\DeleteDocument; diff --git a/app/BulkActions/Sales/Invoices.php b/app/BulkActions/Sales/Invoices.php index 07e78051b..a079531d5 100644 --- a/app/BulkActions/Sales/Invoices.php +++ b/app/BulkActions/Sales/Invoices.php @@ -7,7 +7,7 @@ use App\Events\Document\DocumentCancelled; use App\Events\Document\DocumentCreated; use App\Events\Document\DocumentMarkedSent; use App\Events\Document\PaymentReceived; -use App\Exports\Sales\Invoices as Export; +use App\Exports\Sales\Invoices\Invoices as Export; use App\Jobs\Document\DeleteDocument; use App\Models\Document\Document; diff --git a/app/Exports/Banking/RecurringTransactions.php b/app/Exports/Banking/RecurringTransactions.php new file mode 100644 index 000000000..87d51745c --- /dev/null +++ b/app/Exports/Banking/RecurringTransactions.php @@ -0,0 +1,28 @@ +ids = $ids; + } + + public function sheets(): array + { + return [ + new Recurring($this->ids), + new Base($this->ids), + ]; + } +} diff --git a/app/Exports/Banking/Sheets/Recurring.php b/app/Exports/Banking/Sheets/Recurring.php new file mode 100644 index 000000000..286a19359 --- /dev/null +++ b/app/Exports/Banking/Sheets/Recurring.php @@ -0,0 +1,36 @@ +cursor(); + } + + public function map($model): array + { + $model->transaction_number = $model->recurable->number; + + return parent::map($model); + } + + public function fields(): array + { + return [ + 'recurable_type', + 'transaction_number', + 'frequency', + 'interval', + 'started_at', + 'status', + 'limit_by', + 'limit_count', + 'auto_send', + ]; + } +} diff --git a/app/Exports/Banking/Sheets/RecurringTransactions.php b/app/Exports/Banking/Sheets/RecurringTransactions.php new file mode 100644 index 000000000..5e4b44ca5 --- /dev/null +++ b/app/Exports/Banking/Sheets/RecurringTransactions.php @@ -0,0 +1,53 @@ +isRecurring()->cursor(); + } + + public function map($model): array + { + $model->account_name = $model->account->name; + $model->contact_email = $model->contact->email; + $model->category_name = $model->category->name; + $model->invoice_bill_number = $model->document->document_number ?? 0; + + return parent::map($model); + } + + public function fields(): array + { + return [ + 'type', + 'number', + 'paid_at', + 'amount', + 'currency_code', + 'currency_rate', + 'account_name', + 'invoice_bill_number', + 'contact_email', + 'category_name', + 'description', + 'payment_method', + 'reference', + 'reconciled', + ]; + } + + public function columnFormats(): array + { + return [ + 'C' => NumberFormat::FORMAT_DATE_YYYYMMDD, + ]; + } +} diff --git a/app/Exports/Purchases/Bills.php b/app/Exports/Purchases/Bills/Bills.php similarity index 62% rename from app/Exports/Purchases/Bills.php rename to app/Exports/Purchases/Bills/Bills.php index 3a5a9115b..dd4213e52 100644 --- a/app/Exports/Purchases/Bills.php +++ b/app/Exports/Purchases/Bills/Bills.php @@ -1,13 +1,13 @@ ids = $ids; + } + + public function sheets(): array + { + return [ + new Recurring($this->ids), + new Base($this->ids), + new RecurringBillItems($this->ids), + new RecurringBillItemTaxes($this->ids), + new RecurringBillHistories($this->ids), + new RecurringBillTotals($this->ids), + ]; + } +} diff --git a/app/Exports/Purchases/RecurringBills/Sheets/Recurring.php b/app/Exports/Purchases/RecurringBills/Sheets/Recurring.php new file mode 100644 index 000000000..20ef7354c --- /dev/null +++ b/app/Exports/Purchases/RecurringBills/Sheets/Recurring.php @@ -0,0 +1,36 @@ +cursor(); + } + + public function map($model): array + { + $model->bill_number = $model->recurable->document_number; + + return parent::map($model); + } + + public function fields(): array + { + return [ + 'recurable_type', + 'bill_number', + 'frequency', + 'interval', + 'started_at', + 'status', + 'limit_by', + 'limit_count', + 'auto_send', + ]; + } +} diff --git a/app/Exports/Purchases/RecurringBills/Sheets/RecurringBillHistories.php b/app/Exports/Purchases/RecurringBills/Sheets/RecurringBillHistories.php new file mode 100644 index 000000000..41af4ea76 --- /dev/null +++ b/app/Exports/Purchases/RecurringBills/Sheets/RecurringBillHistories.php @@ -0,0 +1,37 @@ +billRecurring()->collectForExport($this->ids, null, 'document_id'); + } + + public function map($model): array + { + $document = $model->document; + + if (empty($document)) { + return []; + } + + $model->bill_number = $document->document_number; + + return parent::map($model); + } + + public function fields(): array + { + return [ + 'bill_number', + 'status', + 'notify', + 'description', + ]; + } +} diff --git a/app/Exports/Purchases/RecurringBills/Sheets/RecurringBillItemTaxes.php b/app/Exports/Purchases/RecurringBills/Sheets/RecurringBillItemTaxes.php new file mode 100644 index 000000000..1249a8160 --- /dev/null +++ b/app/Exports/Purchases/RecurringBills/Sheets/RecurringBillItemTaxes.php @@ -0,0 +1,39 @@ +billRecurring()->collectForExport($this->ids, null, 'document_id'); + } + + public function map($model): array + { + $document = $model->document; + + if (empty($document)) { + return []; + } + + $model->bill_number = $document->document_number; + $model->item_name = $model->item->name; + $model->tax_rate = $model->tax->rate; + + return parent::map($model); + } + + public function fields(): array + { + return [ + 'bill_number', + 'item_name', + 'tax_rate', + 'amount', + ]; + } +} diff --git a/app/Exports/Purchases/RecurringBills/Sheets/RecurringBillItems.php b/app/Exports/Purchases/RecurringBills/Sheets/RecurringBillItems.php new file mode 100644 index 000000000..1e7eb345e --- /dev/null +++ b/app/Exports/Purchases/RecurringBills/Sheets/RecurringBillItems.php @@ -0,0 +1,44 @@ +billRecurring()->collectForExport($this->ids, null, 'document_id'); + } + + public function map($model): array + { + $document = $model->document; + + if (empty($document)) { + return []; + } + + $model->bill_number = $document->document_number; + $model->item_name = $model->item->name; + $model->item_description = $model->item->description; + $model->item_type = $model->item->type; + + return parent::map($model); + } + + public function fields(): array + { + return [ + 'bill_number', + 'item_name', + 'item_description', + 'item_type', + 'quantity', + 'price', + 'total', + 'tax', + ]; + } +} diff --git a/app/Exports/Purchases/RecurringBills/Sheets/RecurringBillTotals.php b/app/Exports/Purchases/RecurringBills/Sheets/RecurringBillTotals.php new file mode 100644 index 000000000..fdaadafc6 --- /dev/null +++ b/app/Exports/Purchases/RecurringBills/Sheets/RecurringBillTotals.php @@ -0,0 +1,38 @@ +billRecurring()->collectForExport($this->ids, null, 'document_id'); + } + + public function map($model): array + { + $document = $model->document; + + if (empty($document)) { + return []; + } + + $model->bill_number = $document->document_number; + + return parent::map($model); + } + + public function fields(): array + { + return [ + 'bill_number', + 'code', + 'name', + 'amount', + 'sort_order', + ]; + } +} diff --git a/app/Exports/Purchases/RecurringBills/Sheets/RecurringBills.php b/app/Exports/Purchases/RecurringBills/Sheets/RecurringBills.php new file mode 100644 index 000000000..beda1e22c --- /dev/null +++ b/app/Exports/Purchases/RecurringBills/Sheets/RecurringBills.php @@ -0,0 +1,65 @@ +billRecurring()->collectForExport($this->ids, ['document_number' => 'desc']); + } + + public function map($model): array + { + $country = null; + + if ($model->contact_country && array_key_exists($model->contact_country, trans('countries'))) { + $country = trans('countries.' . $model->contact_country); + } + + $model->category_name = $model->category->name; + $model->bill_number = $model->document_number; + $model->billed_at = $model->issued_at; + $model->contact_country = $country; + + return parent::map($model); + } + + public function fields(): array + { + return [ + 'bill_number', + 'order_number', + 'status', + 'billed_at', + 'due_at', + 'amount', + 'currency_code', + 'currency_rate', + 'category_name', + 'contact_name', + 'contact_email', + 'contact_tax_number', + 'contact_phone', + 'contact_address', + 'contact_country', + 'contact_state', + 'contact_zip_code', + 'contact_city', + 'notes', + ]; + } + + public function columnFormats(): array + { + return [ + 'D' => NumberFormat::FORMAT_DATE_YYYYMMDD, + 'E' => NumberFormat::FORMAT_DATE_YYYYMMDD, + ]; + } +} diff --git a/app/Exports/Sales/Invoices.php b/app/Exports/Sales/Invoices/Invoices.php similarity index 62% rename from app/Exports/Sales/Invoices.php rename to app/Exports/Sales/Invoices/Invoices.php index 3c2148d96..d24ba473e 100644 --- a/app/Exports/Sales/Invoices.php +++ b/app/Exports/Sales/Invoices/Invoices.php @@ -1,13 +1,13 @@ ids = $ids; + } + + public function sheets(): array + { + return [ + new Recurring($this->ids), + new Base($this->ids), + new RecurringInvoiceItems($this->ids), + new RecurringInvoiceItemTaxes($this->ids), + new RecurringInvoiceHistories($this->ids), + new RecurringInvoiceTotals($this->ids), + ]; + } +} diff --git a/app/Exports/Sales/RecurringInvoices/Sheets/Recurring.php b/app/Exports/Sales/RecurringInvoices/Sheets/Recurring.php new file mode 100644 index 000000000..08048a4fa --- /dev/null +++ b/app/Exports/Sales/RecurringInvoices/Sheets/Recurring.php @@ -0,0 +1,36 @@ +cursor(); + } + + public function map($model): array + { + $model->invoice_number = $model->recurable->document_number; + + return parent::map($model); + } + + public function fields(): array + { + return [ + 'recurable_type', + 'invoice_number', + 'frequency', + 'interval', + 'started_at', + 'status', + 'limit_by', + 'limit_count', + 'auto_send', + ]; + } +} diff --git a/app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceHistories.php b/app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceHistories.php new file mode 100644 index 000000000..df0dd0727 --- /dev/null +++ b/app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceHistories.php @@ -0,0 +1,37 @@ +invoiceRecurring()->collectForExport($this->ids, null, 'document_id'); + } + + public function map($model): array + { + $document = $model->document; + + if (empty($document)) { + return []; + } + + $model->invoice_number = $document->document_number; + + return parent::map($model); + } + + public function fields(): array + { + return [ + 'invoice_number', + 'status', + 'notify', + 'description', + ]; + } +} diff --git a/app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItemTaxes.php b/app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItemTaxes.php new file mode 100644 index 000000000..fcf783945 --- /dev/null +++ b/app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItemTaxes.php @@ -0,0 +1,39 @@ +invoiceRecurring()->collectForExport($this->ids, null, 'document_id'); + } + + public function map($model): array + { + $document = $model->document; + + if (empty($document)) { + return []; + } + + $model->invoice_number = $document->document_number; + $model->item_name = $model->item->name; + $model->tax_rate = $model->tax->rate; + + return parent::map($model); + } + + public function fields(): array + { + return [ + 'invoice_number', + 'item_name', + 'tax_rate', + 'amount', + ]; + } +} diff --git a/app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItems.php b/app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItems.php new file mode 100644 index 000000000..fabc31c80 --- /dev/null +++ b/app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItems.php @@ -0,0 +1,44 @@ +invoiceRecurring()->collectForExport($this->ids, null, 'document_id'); + } + + public function map($model): array + { + $document = $model->document; + + if (empty($document)) { + return []; + } + + $model->invoice_number = $document->document_number; + $model->item_name = $model->item->name; + $model->item_description = $model->item->description; + $model->item_type = $model->item->type; + + return parent::map($model); + } + + public function fields(): array + { + return [ + 'invoice_number', + 'item_name', + 'item_description', + 'item_type', + 'quantity', + 'price', + 'total', + 'tax', + ]; + } +} diff --git a/app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceTotals.php b/app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceTotals.php new file mode 100644 index 000000000..8d7b7af4f --- /dev/null +++ b/app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoiceTotals.php @@ -0,0 +1,38 @@ +invoiceRecurring()->collectForExport($this->ids, null, 'document_id'); + } + + public function map($model): array + { + $document = $model->document; + + if (empty($document)) { + return []; + } + + $model->invoice_number = $document->document_number; + + return parent::map($model); + } + + public function fields(): array + { + return [ + 'invoice_number', + 'code', + 'name', + 'amount', + 'sort_order', + ]; + } +} diff --git a/app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoices.php b/app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoices.php new file mode 100644 index 000000000..923ee94e3 --- /dev/null +++ b/app/Exports/Sales/RecurringInvoices/Sheets/RecurringInvoices.php @@ -0,0 +1,67 @@ +invoiceRecurring()->collectForExport($this->ids, ['document_number' => 'desc']); + } + + public function map($model): array + { + $country = null; + + if ($model->contact_country && array_key_exists($model->contact_country, trans('countries'))) { + $country = trans('countries.' . $model->contact_country); + } + + $model->category_name = $model->category->name; + $model->invoice_number = $model->document_number; + $model->invoiced_at = $model->issued_at; + $model->contact_country = $country; + + + return parent::map($model); + } + + public function fields(): array + { + return [ + 'invoice_number', + 'order_number', + 'status', + 'invoiced_at', + 'due_at', + 'amount', + 'currency_code', + 'currency_rate', + 'category_name', + 'contact_name', + 'contact_email', + 'contact_tax_number', + 'contact_phone', + 'contact_address', + 'contact_country', + 'contact_state', + 'contact_zip_code', + 'contact_city', + 'notes', + 'footer', + ]; + } + + public function columnFormats(): array + { + return [ + 'D' => NumberFormat::FORMAT_DATE_YYYYMMDD, + 'E' => NumberFormat::FORMAT_DATE_YYYYMMDD, + ]; + } +} diff --git a/app/Http/Controllers/Banking/RecurringTransactions.php b/app/Http/Controllers/Banking/RecurringTransactions.php index 2f15bc89c..21ee0314c 100644 --- a/app/Http/Controllers/Banking/RecurringTransactions.php +++ b/app/Http/Controllers/Banking/RecurringTransactions.php @@ -3,7 +3,10 @@ namespace App\Http\Controllers\Banking; use App\Abstracts\Http\Controller; +use App\Exports\Banking\RecurringTransactions as Export; use App\Http\Requests\Banking\Transaction as Request; +use App\Http\Requests\Common\Import as ImportRequest; +use App\Imports\Banking\RecurringTransactions as Import; use App\Jobs\Banking\CreateTransaction; use App\Jobs\Banking\UpdateTransaction; use App\Models\Banking\Account; @@ -97,7 +100,7 @@ class RecurringTransactions extends Controller if ($response['success']) { $response['redirect'] = route('recurring-transactions.show', $response['data']->id); - $message = trans('messages.success.added', ['type' => trans_choice('general.transactions', 1)]); + $message = trans('messages.success.added', ['type' => trans_choice('general.recurring_transactions', 1)]); flash($message)->success(); } else { @@ -122,13 +125,37 @@ class RecurringTransactions extends Controller { $clone = $recurring_transaction->duplicate(); - $message = trans('messages.success.duplicated', ['type' => trans_choice('general.transactions', 1)]); + $message = trans('messages.success.duplicated', ['type' => trans_choice('general.recurring_transactions', 1)]); flash($message)->success(); return redirect()->route('recurring-transactions.edit', $clone->id); } + /** + * Import the specified resource. + * + * @param ImportRequest $request + * + * @return Response + */ + public function import(ImportRequest $request) + { + $response = $this->importExcel(new Import, $request, trans_choice('general.recurring_transactions', 2)); + + if ($response['success']) { + $response['redirect'] = route('recurring-transactions.index'); + + flash($response['message'])->success(); + } else { + $response['redirect'] = route('import.create', ['banking', 'recurring-transactions']); + + flash($response['message'])->error()->important(); + } + + return response()->json($response); + } + /** * Show the form for editing the specified resource. * @@ -174,7 +201,7 @@ class RecurringTransactions extends Controller if ($response['success']) { $response['redirect'] = route('recurring-transactions.show', $recurring_transaction->id); - $message = trans('messages.success.updated', ['type' => trans_choice('general.transactions', 1)]); + $message = trans('messages.success.updated', ['type' => trans_choice('general.recurring_transactions', 1)]); flash($message)->success(); } else { @@ -187,6 +214,16 @@ class RecurringTransactions extends Controller return response()->json($response); } + + /** + * Export the specified resource. + * + * @return Response + */ + public function export() + { + return $this->exportExcel(new Export, trans_choice('general.recurring_transactions', 2)); + } /** * End recurring template. diff --git a/app/Http/Controllers/Purchases/Bills.php b/app/Http/Controllers/Purchases/Bills.php index 5465fd625..69b615cfc 100644 --- a/app/Http/Controllers/Purchases/Bills.php +++ b/app/Http/Controllers/Purchases/Bills.php @@ -3,10 +3,10 @@ namespace App\Http\Controllers\Purchases; use App\Abstracts\Http\Controller; -use App\Exports\Purchases\Bills as Export; +use App\Exports\Purchases\Bills\Bills as Export; use App\Http\Requests\Common\Import as ImportRequest; use App\Http\Requests\Document\Document as Request; -use App\Imports\Purchases\Bills as Import; +use App\Imports\Purchases\Bills\Bills as Import; use App\Jobs\Document\CreateDocument; use App\Jobs\Document\DeleteDocument; use App\Jobs\Document\DuplicateDocument; diff --git a/app/Http/Controllers/Purchases/RecurringBills.php b/app/Http/Controllers/Purchases/RecurringBills.php index 4fb9f874f..ffa34b579 100644 --- a/app/Http/Controllers/Purchases/RecurringBills.php +++ b/app/Http/Controllers/Purchases/RecurringBills.php @@ -3,7 +3,10 @@ namespace App\Http\Controllers\Purchases; use App\Abstracts\Http\Controller; +use App\Exports\Purchases\RecurringBills\RecurringBills as Export; +use App\Http\Requests\Common\Import as ImportRequest; use App\Http\Requests\Document\Document as Request; +use App\Imports\Purchases\RecurringBills\RecurringBills as Import; use App\Jobs\Document\CreateDocument; use App\Jobs\Document\DuplicateDocument; use App\Jobs\Document\UpdateDocument; @@ -114,6 +117,30 @@ class RecurringBills extends Controller return redirect()->route('recurring-bills.edit', $clone->id); } + /** + * Import the specified resource. + * + * @param ImportRequest $request + * + * @return Response + */ + public function import(ImportRequest $request) + { + $response = $this->importExcel(new Import, $request, trans_choice('general.recurring_bills', 2)); + + if ($response['success']) { + $response['redirect'] = route('recurring-bills.index'); + + flash($response['message'])->success(); + } else { + $response['redirect'] = route('import.create', ['purchases', 'recurring-bills']); + + flash($response['message'])->error()->important(); + } + + return response()->json($response); + } + /** * Show the form for editing the specified resource. * @@ -155,6 +182,16 @@ class RecurringBills extends Controller return response()->json($response); } + /** + * Export the specified resource. + * + * @return Response + */ + public function export() + { + return $this->exportExcel(new Export, trans_choice('general.recurring_bills', 2)); + } + /** * End recurring template. * diff --git a/app/Http/Controllers/Sales/Invoices.php b/app/Http/Controllers/Sales/Invoices.php index 3730c5d18..4dc622d51 100644 --- a/app/Http/Controllers/Sales/Invoices.php +++ b/app/Http/Controllers/Sales/Invoices.php @@ -3,10 +3,10 @@ namespace App\Http\Controllers\Sales; use App\Abstracts\Http\Controller; -use App\Exports\Sales\Invoices as Export; +use App\Exports\Sales\Invoices\Invoices as Export; use App\Http\Requests\Common\Import as ImportRequest; use App\Http\Requests\Document\Document as Request; -use App\Imports\Sales\Invoices as Import; +use App\Imports\Sales\Invoices\Invoices as Import; use App\Jobs\Document\CreateDocument; use App\Jobs\Document\DeleteDocument; use App\Jobs\Document\DuplicateDocument; diff --git a/app/Http/Controllers/Sales/RecurringInvoices.php b/app/Http/Controllers/Sales/RecurringInvoices.php index 265e036f6..e1a0bec87 100644 --- a/app/Http/Controllers/Sales/RecurringInvoices.php +++ b/app/Http/Controllers/Sales/RecurringInvoices.php @@ -3,7 +3,10 @@ namespace App\Http\Controllers\Sales; use App\Abstracts\Http\Controller; +use App\Exports\Sales\RecurringInvoices\RecurringInvoices as Export; +use App\Http\Requests\Common\Import as ImportRequest; use App\Http\Requests\Document\Document as Request; +use App\Imports\Sales\RecurringInvoices\RecurringInvoices as Import; use App\Jobs\Document\CreateDocument; use App\Jobs\Document\DuplicateDocument; use App\Jobs\Document\UpdateDocument; @@ -114,6 +117,30 @@ class RecurringInvoices extends Controller return redirect()->route('recurring-invoices.edit', $clone->id); } + /** + * Import the specified resource. + * + * @param ImportRequest $request + * + * @return Response + */ + public function import(ImportRequest $request) + { + $response = $this->importExcel(new Import, $request, trans_choice('general.recurring_invoices', 2)); + + if ($response['success']) { + $response['redirect'] = route('recurring-invoices.index'); + + flash($response['message'])->success(); + } else { + $response['redirect'] = route('import.create', ['sales', 'recurring-invoices']); + + flash($response['message'])->error()->important(); + } + + return response()->json($response); + } + /** * Show the form for editing the specified resource. * @@ -155,6 +182,16 @@ class RecurringInvoices extends Controller return response()->json($response); } + /** + * Export the specified resource. + * + * @return Response + */ + public function export() + { + return $this->exportExcel(new Export, trans_choice('general.recurring_invoices', 2)); + } + /** * End recurring template. * diff --git a/app/Imports/Banking/RecurringTransactions.php b/app/Imports/Banking/RecurringTransactions.php new file mode 100644 index 000000000..22670959f --- /dev/null +++ b/app/Imports/Banking/RecurringTransactions.php @@ -0,0 +1,18 @@ + new Base(), + 'recurring' => new Recurring(), + ]; + } +} diff --git a/app/Imports/Banking/Sheets/Recurring.php b/app/Imports/Banking/Sheets/Recurring.php new file mode 100644 index 000000000..3d9ac9577 --- /dev/null +++ b/app/Imports/Banking/Sheets/Recurring.php @@ -0,0 +1,24 @@ +number($row['transaction_number'])->pluck('id')->first(); + + return $row; + } +} diff --git a/app/Imports/Banking/Sheets/RecurringTransactions.php b/app/Imports/Banking/Sheets/RecurringTransactions.php new file mode 100644 index 000000000..bdec04a77 --- /dev/null +++ b/app/Imports/Banking/Sheets/RecurringTransactions.php @@ -0,0 +1,38 @@ +getCurrencyCode($row); + $row['account_id'] = $this->getAccountId($row); + $row['category_id'] = $this->getCategoryId($row, $transaction_type); + $row['contact_id'] = $this->getContactId($row, $transaction_type); + + if ($transaction_type == 'income') { + $row['document_id'] = Document::invoiceRecurring()->number($row['invoice_bill_number'])->pluck('id')->first(); + } else { + $row['document_id'] = Document::billRecurring()->number($row['invoice_bill_number'])->pluck('id')->first(); + } + + return $row; + } +} diff --git a/app/Imports/Purchases/Bills.php b/app/Imports/Purchases/Bills/Bills.php similarity index 56% rename from app/Imports/Purchases/Bills.php rename to app/Imports/Purchases/Bills/Bills.php index 18b383af2..541d98899 100644 --- a/app/Imports/Purchases/Bills.php +++ b/app/Imports/Purchases/Bills/Bills.php @@ -1,14 +1,14 @@ new Base(), + 'recurring_bill_items' => new RecurringBillItems(), + 'recurring_bill_item_taxes' => new RecurringBillItemTaxes(), + 'recurring_bill_histories' => new RecurringBillHistories(), + 'recurring_bill_totals' => new RecurringBillTotals(), + 'recurring' => new Recurring(), + ]; + } +} diff --git a/app/Imports/Purchases/RecurringBills/Sheets/Recurring.php b/app/Imports/Purchases/RecurringBills/Sheets/Recurring.php new file mode 100644 index 000000000..da034faa0 --- /dev/null +++ b/app/Imports/Purchases/RecurringBills/Sheets/Recurring.php @@ -0,0 +1,27 @@ +number($row['bill_number']) + ->pluck('id') + ->first(); + + return $row; + } +} diff --git a/app/Imports/Purchases/RecurringBills/Sheets/RecurringBillHistories.php b/app/Imports/Purchases/RecurringBills/Sheets/RecurringBillHistories.php new file mode 100644 index 000000000..fafa4a14a --- /dev/null +++ b/app/Imports/Purchases/RecurringBills/Sheets/RecurringBillHistories.php @@ -0,0 +1,49 @@ +isEmpty($row, 'bill_number')) { + return []; + } + + $row['bill_number'] = (string) $row['bill_number']; + + $row = parent::map($row); + + $row['document_id'] = (int) Document::where('type', '=', Document::BILL_RECURRING_TYPE) + ->number($row['bill_number']) + ->pluck('id') + ->first(); + + $row['notify'] = (int) $row['notify']; + + $row['type'] = Document::BILL_RECURRING_TYPE; + + return $row; + } + + public function prepareRules(array $rules): array + { + $rules['bill_number'] = 'required|string'; + + unset($rules['bill_id']); + + return $rules; + } +} diff --git a/app/Imports/Purchases/RecurringBills/Sheets/RecurringBillItemTaxes.php b/app/Imports/Purchases/RecurringBills/Sheets/RecurringBillItemTaxes.php new file mode 100644 index 000000000..daf80a71c --- /dev/null +++ b/app/Imports/Purchases/RecurringBills/Sheets/RecurringBillItemTaxes.php @@ -0,0 +1,66 @@ +isEmpty($row, 'bill_number')) { + return []; + } + + $row['bill_number'] = (string) $row['bill_number']; + + $row = parent::map($row); + + $row['document_id'] = (int) Document::where('type', '=', Document::BILL_RECURRING_TYPE) + ->number($row['bill_number']) + ->pluck('id') + ->first(); + + if (empty($row['document_item_id']) && !empty($row['item_name'])) { + $item_id = Item::name($row['item_name'])->pluck('id')->first(); + + $row['document_item_id'] = DocumentItem::where('type', '=', Document::BILL_RECURRING_TYPE) + ->where('item_id', $item_id) + ->pluck('id') + ->first(); + } + + $row['tax_id'] = $this->getTaxId($row); + + if (empty($row['name']) && !empty($row['item_name'])) { + $row['name'] = $row['item_name']; + } + + $row['amount'] = (double) $row['amount']; + + $row['type'] = Document::BILL_RECURRING_TYPE; + + return $row; + } + + public function prepareRules(array $rules): array + { + $rules['bill_number'] = 'required|string'; + + unset($rules['bill_id']); + + return $rules; + } +} diff --git a/app/Imports/Purchases/RecurringBills/Sheets/RecurringBillItems.php b/app/Imports/Purchases/RecurringBills/Sheets/RecurringBillItems.php new file mode 100644 index 000000000..9a4ac6ca3 --- /dev/null +++ b/app/Imports/Purchases/RecurringBills/Sheets/RecurringBillItems.php @@ -0,0 +1,57 @@ +isEmpty($row, 'bill_number')) { + return []; + } + + $row['bill_number'] = (string) $row['bill_number']; + + $row = parent::map($row); + + $row['document_id'] = (int) Document::where('type', '=', Document::BILL_RECURRING_TYPE) + ->number($row['bill_number']) + ->pluck('id') + ->first(); + + if (empty($row['item_id']) && !empty($row['item_name'])) { + $row['item_id'] = $this->getItemIdFromName($row); + + $row['name'] = $row['item_name']; + } + + $row['description'] = !empty($row['item_description']) ? $row['item_description'] : ''; + + $row['tax'] = (double) $row['tax']; + $row['tax_id'] = 0; + $row['type'] = Document::BILL_RECURRING_TYPE; + + return $row; + } + + public function prepareRules(array $rules): array + { + $rules['bill_number'] = 'required|string'; + + unset($rules['bill_id']); + + return $rules; + } +} diff --git a/app/Imports/Purchases/RecurringBills/Sheets/RecurringBillTotals.php b/app/Imports/Purchases/RecurringBills/Sheets/RecurringBillTotals.php new file mode 100644 index 000000000..d0038cef9 --- /dev/null +++ b/app/Imports/Purchases/RecurringBills/Sheets/RecurringBillTotals.php @@ -0,0 +1,47 @@ +isEmpty($row, 'bill_number')) { + return []; + } + + $row['bill_number'] = (string) $row['bill_number']; + + $row = parent::map($row); + + $row['document_id'] = (int) Document::where('type', '=', Document::BILL_RECURRING_TYPE) + ->number($row['bill_number']) + ->pluck('id') + ->first(); + + $row['type'] = Document::BILL_RECURRING_TYPE; + + return $row; + } + + public function prepareRules(array $rules): array + { + $rules['bill_number'] = 'required|string'; + + unset($rules['bill_id']); + + return $rules; + } +} diff --git a/app/Imports/Purchases/RecurringBills/Sheets/RecurringBills.php b/app/Imports/Purchases/RecurringBills/Sheets/RecurringBills.php new file mode 100644 index 000000000..f52582643 --- /dev/null +++ b/app/Imports/Purchases/RecurringBills/Sheets/RecurringBills.php @@ -0,0 +1,52 @@ +isEmpty($row, 'bill_number')) { + return []; + } + + $row['bill_number'] = (string) $row['bill_number']; + + $row = parent::map($row); + + $country = array_search($row['contact_country'], trans('countries')); + + $row['document_number'] = $row['bill_number']; + $row['issued_at'] = $row['billed_at']; + $row['category_id'] = $this->getCategoryId($row, 'expense'); + $row['contact_id'] = $this->getContactId($row, 'vendor'); + $row['currency_code'] = $this->getCurrencyCode($row); + $row['type'] = Model::BILL_RECURRING_TYPE; + $row['contact_country'] = !empty($country) ? $country : null; + + return $row; + } + + public function prepareRules(array $rules): array + { + $rules['bill_number'] = Str::replaceFirst('unique:documents,NULL', 'unique:documents,document_number', $rules['document_number']); + $rules['billed_at'] = $rules['issued_at']; + $rules['currency_rate'] = 'required|gt:0'; + + unset($rules['document_number'], $rules['issued_at'], $rules['type']); + + return $rules; + } +} diff --git a/app/Imports/Sales/Invoices.php b/app/Imports/Sales/Invoices/Invoices.php similarity index 57% rename from app/Imports/Sales/Invoices.php rename to app/Imports/Sales/Invoices/Invoices.php index 278091650..7dfa1b274 100644 --- a/app/Imports/Sales/Invoices.php +++ b/app/Imports/Sales/Invoices/Invoices.php @@ -1,14 +1,14 @@ new Base(), + 'recurring_invoice_items' => new RecurringInvoiceItems(), + 'recurring_invoice_item_taxes' => new RecurringInvoiceItemTaxes(), + 'recurring_invoice_histories' => new RecurringInvoiceHistories(), + 'recurring_invoice_totals' => new RecurringInvoiceTotals(), + 'recurring' => new Recurring(), + ]; + } +} diff --git a/app/Imports/Sales/RecurringInvoices/Sheets/Recurring.php b/app/Imports/Sales/RecurringInvoices/Sheets/Recurring.php new file mode 100644 index 000000000..bf71f3ef9 --- /dev/null +++ b/app/Imports/Sales/RecurringInvoices/Sheets/Recurring.php @@ -0,0 +1,27 @@ +number($row['invoice_number']) + ->pluck('id') + ->first(); + + return $row; + } +} diff --git a/app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceHistories.php b/app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceHistories.php new file mode 100644 index 000000000..f04c36c64 --- /dev/null +++ b/app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceHistories.php @@ -0,0 +1,49 @@ +isEmpty($row, 'invoice_number')) { + return []; + } + + $row['invoice_number'] = (string) $row['invoice_number']; + + $row = parent::map($row); + + $row['document_id'] = (int) Document::where('type', '=', Document::INVOICE_RECURRING_TYPE) + ->number($row['invoice_number']) + ->pluck('id') + ->first(); + + $row['notify'] = (int) $row['notify']; + + $row['type'] = Document::INVOICE_RECURRING_TYPE; + + return $row; + } + + public function prepareRules(array $rules): array + { + $rules['invoice_number'] = 'required|string'; + + unset($rules['invoice_id']); + + return $rules; + } +} diff --git a/app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItemTaxes.php b/app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItemTaxes.php new file mode 100644 index 000000000..8b7c633d3 --- /dev/null +++ b/app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItemTaxes.php @@ -0,0 +1,66 @@ +isEmpty($row, 'invoice_number')) { + return []; + } + + $row['invoice_number'] = (string) $row['invoice_number']; + + $row = parent::map($row); + + $row['document_id'] = (int) Document::where('type', '=', Document::INVOICE_RECURRING_TYPE) + ->number($row['invoice_number']) + ->pluck('id') + ->first(); + + if (empty($row['document_item_id']) && !empty($row['item_name'])) { + $item_id = Item::name($row['item_name'])->pluck('id')->first(); + + $row['document_item_id'] = DocumentItem::where('type', '=', Document::INVOICE_RECURRING_TYPE) + ->where('item_id', $item_id) + ->pluck('id') + ->first(); + } + + $row['tax_id'] = $this->getTaxId($row); + + if (empty($row['name']) && !empty($row['item_name'])) { + $row['name'] = $row['item_name']; + } + + $row['amount'] = (double) $row['amount']; + + $row['type'] = Document::INVOICE_RECURRING_TYPE; + + return $row; + } + + public function prepareRules(array $rules): array + { + $rules['invoice_number'] = 'required|string'; + + unset($rules['invoice_id']); + + return $rules; + } +} diff --git a/app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItems.php b/app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItems.php new file mode 100644 index 000000000..5f134e399 --- /dev/null +++ b/app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceItems.php @@ -0,0 +1,57 @@ +isEmpty($row, 'invoice_number')) { + return []; + } + + $row['invoice_number'] = (string) $row['invoice_number']; + + $row = parent::map($row); + + $row['document_id'] = (int) Document::where('type', '=', Document::INVOICE_RECURRING_TYPE) + ->number($row['invoice_number']) + ->pluck('id') + ->first(); + + if (empty($row['item_id']) && ! empty($row['item_name'])) { + $row['item_id'] = $this->getItemIdFromName($row); + + $row['name'] = $row['item_name']; + } + + $row['description'] = !empty($row['item_description']) ? $row['item_description'] : ''; + + $row['tax'] = (double) $row['tax']; + $row['tax_id'] = 0; + $row['type'] = Document::INVOICE_RECURRING_TYPE; + + return $row; + } + + public function prepareRules(array $rules): array + { + $rules['invoice_number'] = 'required|string'; + + unset($rules['invoice_id']); + + return $rules; + } +} diff --git a/app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceTotals.php b/app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceTotals.php new file mode 100644 index 000000000..1dd454207 --- /dev/null +++ b/app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoiceTotals.php @@ -0,0 +1,47 @@ +isEmpty($row, 'invoice_number')) { + return []; + } + + $row['invoice_number'] = (string) $row['invoice_number']; + + $row = parent::map($row); + + $row['document_id'] = (int) Document::where('type', '=', Document::INVOICE_RECURRING_TYPE) + ->number($row['invoice_number']) + ->pluck('id') + ->first(); + + $row['type'] = Document::INVOICE_RECURRING_TYPE; + + return $row; + } + + public function prepareRules(array $rules): array + { + $rules['invoice_number'] = 'required|string'; + + unset($rules['invoice_id']); + + return $rules; + } +} diff --git a/app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoices.php b/app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoices.php new file mode 100644 index 000000000..fb4dd810d --- /dev/null +++ b/app/Imports/Sales/RecurringInvoices/Sheets/RecurringInvoices.php @@ -0,0 +1,52 @@ +isEmpty($row, 'invoice_number')) { + return []; + } + + $row['invoice_number'] = (string) $row['invoice_number']; + + $row = parent::map($row); + + $country = array_search($row['contact_country'], trans('countries')); + + $row['document_number'] = $row['invoice_number']; + $row['issued_at'] = $row['invoiced_at']; + $row['category_id'] = $this->getCategoryId($row, 'income'); + $row['contact_id'] = $this->getContactId($row, 'customer'); + $row['currency_code'] = $this->getCurrencyCode($row); + $row['type'] = Model::INVOICE_RECURRING_TYPE; + $row['contact_country'] = !empty($country) ? $country : null; + + return $row; + } + + public function prepareRules(array $rules): array + { + $rules['invoice_number'] = Str::replaceFirst('unique:documents,NULL', 'unique:documents,document_number', $rules['document_number']); + $rules['invoiced_at'] = $rules['issued_at']; + $rules['currency_rate'] = 'required|gt:0'; + + unset($rules['document_number'], $rules['issued_at'], $rules['type']); + + return $rules; + } +} diff --git a/public/files/import/recurring-bills.xlsx b/public/files/import/recurring-bills.xlsx new file mode 100644 index 000000000..9bbc38bc6 Binary files /dev/null and b/public/files/import/recurring-bills.xlsx differ diff --git a/public/files/import/recurring-invoices.xlsx b/public/files/import/recurring-invoices.xlsx new file mode 100644 index 000000000..eea3bc376 Binary files /dev/null and b/public/files/import/recurring-invoices.xlsx differ diff --git a/public/files/import/recurring-transactions.xlsx b/public/files/import/recurring-transactions.xlsx new file mode 100644 index 000000000..0adc49828 Binary files /dev/null and b/public/files/import/recurring-transactions.xlsx differ diff --git a/resources/views/banking/recurring_transactions/index.blade.php b/resources/views/banking/recurring_transactions/index.blade.php index fad645a4a..fec5c155c 100644 --- a/resources/views/banking/recurring_transactions/index.blade.php +++ b/resources/views/banking/recurring_transactions/index.blade.php @@ -21,6 +21,24 @@ @endcan + + + + more_horiz + + + @can('create-banking-transactions') + + {{ trans('import.import') }} + + @endcan + + + {{ trans('general.export') }} + + + + @if ($transactions->count() || request()->get('search', false)) @@ -141,23 +159,29 @@ @endif diff --git a/resources/views/purchases/recurring_bills/index.blade.php b/resources/views/purchases/recurring_bills/index.blade.php index 262790cb1..6127bbb1f 100644 --- a/resources/views/purchases/recurring_bills/index.blade.php +++ b/resources/views/purchases/recurring_bills/index.blade.php @@ -14,7 +14,7 @@ - + diff --git a/resources/views/sales/recurring_invoices/index.blade.php b/resources/views/sales/recurring_invoices/index.blade.php index b604be522..c978a1151 100644 --- a/resources/views/sales/recurring_invoices/index.blade.php +++ b/resources/views/sales/recurring_invoices/index.blade.php @@ -14,7 +14,7 @@ - + diff --git a/routes/admin.php b/routes/admin.php index 76703b253..ffa504952 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -80,6 +80,8 @@ Route::group(['prefix' => 'sales'], function () { Route::get('recurring-invoices/{recurring_invoice}/duplicate', 'Sales\RecurringInvoices@duplicate')->name('recurring-invoices.duplicate'); Route::get('recurring-invoices/{recurring_invoice}/end', 'Sales\RecurringInvoices@end')->name('recurring-invoices.end'); + Route::post('recurring-invoices/import', 'Sales\RecurringInvoices@import')->middleware('import')->name('recurring-invoices.import'); + Route::get('recurring-invoices/export', 'Sales\RecurringInvoices@export')->name('recurring-invoices.export'); Route::resource('recurring-invoices', 'Sales\RecurringInvoices', ['middleware' => ['date.format', 'money', 'dropzone']]); Route::get('customers/{customer}/create-invoice', 'Sales\Customers@createInvoice')->name('customers.create-invoice'); @@ -104,6 +106,8 @@ Route::group(['prefix' => 'purchases'], function () { Route::get('recurring-bills/{recurring_bill}/duplicate', 'Purchases\RecurringBills@duplicate')->name('recurring-bills.duplicate'); Route::get('recurring-bills/{recurring_bill}/end', 'Purchases\RecurringBills@end')->name('recurring-bills.end'); + Route::post('recurring-bills/import', 'Purchases\RecurringBills@import')->middleware('import')->name('recurring-bills.import'); + Route::get('recurring-bills/export', 'Purchases\RecurringBills@export')->name('recurring-bills.export'); Route::resource('recurring-bills', 'Purchases\RecurringBills', ['middleware' => ['date.format', 'money', 'dropzone']]); Route::get('vendors/{vendor}/create-bill', 'Purchases\Vendors@createBill')->name('vendors.create-bill'); @@ -142,6 +146,8 @@ Route::group(['prefix' => 'banking'], function () { Route::get('recurring-transactions/{recurring_transaction}/duplicate', 'Banking\RecurringTransactions@duplicate')->name('recurring-transactions.duplicate'); Route::get('recurring-transactions/{recurring_transaction}/end', 'Banking\RecurringTransactions@end')->name('recurring-transactions.end'); + Route::post('recurring-transactions/import', 'Banking\RecurringTransactions@import')->middleware('import')->name('recurring-transactions.import'); + Route::get('recurring-transactions/export', 'Banking\RecurringTransactions@export')->name('recurring-transactions.export'); Route::resource('recurring-transactions', 'Banking\RecurringTransactions', ['middleware' => ['date.format', 'money', 'dropzone']]); Route::get('transfers/{transfer}/print', 'Banking\Transfers@printTransfer')->name('transfers.print'); diff --git a/tests/Feature/Purchases/BillsTest.php b/tests/Feature/Purchases/BillsTest.php index bd03a11ba..c879a2ea2 100644 --- a/tests/Feature/Purchases/BillsTest.php +++ b/tests/Feature/Purchases/BillsTest.php @@ -2,7 +2,7 @@ namespace Tests\Feature\Purchases; -use App\Exports\Purchases\Bills as Export; +use App\Exports\Purchases\Bills\Bills as Export; use App\Jobs\Document\CreateDocument; use App\Models\Document\Document; use Illuminate\Http\UploadedFile; diff --git a/tests/Feature/Sales/InvoicesTest.php b/tests/Feature/Sales/InvoicesTest.php index e38d1ba26..3aad6da17 100644 --- a/tests/Feature/Sales/InvoicesTest.php +++ b/tests/Feature/Sales/InvoicesTest.php @@ -2,7 +2,7 @@ namespace Tests\Feature\Sales; -use App\Exports\Sales\Invoices as Export; +use App\Exports\Sales\Invoices\Invoices as Export; use App\Jobs\Document\CreateDocument; use App\Models\Document\Document; use App\Notifications\Sale\Invoice as Notification;