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/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/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/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 @@
-
+