diff --git a/app/Http/Controllers/V1/Admin/Estimate/ChangeEstimateStatusController.php b/app/Http/Controllers/V1/Admin/Estimate/ChangeEstimateStatusController.php deleted file mode 100644 index 93853e09..00000000 --- a/app/Http/Controllers/V1/Admin/Estimate/ChangeEstimateStatusController.php +++ /dev/null @@ -1,27 +0,0 @@ -authorize('send estimate', $estimate); - - $estimate->update($request->only('status')); - - return response()->json([ - 'success' => true, - ]); - } -} diff --git a/app/Http/Controllers/V1/Admin/Estimate/CloneEstimateController.php b/app/Http/Controllers/V1/Admin/Estimate/CloneEstimateController.php deleted file mode 100644 index bd5cc35c..00000000 --- a/app/Http/Controllers/V1/Admin/Estimate/CloneEstimateController.php +++ /dev/null @@ -1,133 +0,0 @@ -authorize('view', $estimate); - $this->authorize('create', Estimate::class); - - $date = Carbon::now(); - - $serial = (new SerialNumberService) - ->setModel($estimate) - ->setCompany($estimate->company_id) - ->setCustomer($estimate->customer_id) - ->setNextNumbers(); - - $due_date = null; - $dueDateEnabled = CompanySetting::getSetting( - 'estimate_set_expiry_date_automatically', - $request->header('company') - ); - - if ($dueDateEnabled === 'YES') { - $dueDateDays = intval(CompanySetting::getSetting( - 'estimate_expiry_date_days', - $request->header('company') - )); - $due_date = Carbon::now()->addDays($dueDateDays)->format('Y-m-d'); - } - - $exchange_rate = $estimate->exchange_rate; - - $newEstimate = Estimate::create([ - 'estimate_date' => $date->format('Y-m-d'), - 'expiry_date' => $due_date, - 'estimate_number' => $serial->getNextNumber(), - 'sequence_number' => $serial->nextSequenceNumber, - 'customer_sequence_number' => $serial->nextCustomerSequenceNumber, - 'reference_number' => $estimate->reference_number, - 'customer_id' => $estimate->customer_id, - 'company_id' => $request->header('company'), - 'template_name' => $estimate->template_name, - 'status' => Estimate::STATUS_DRAFT, - 'sub_total' => $estimate->sub_total, - 'discount' => $estimate->discount, - 'discount_type' => $estimate->discount_type, - 'discount_val' => $estimate->discount_val, - 'total' => $estimate->total, - 'due_amount' => $estimate->total, - 'tax_per_item' => $estimate->tax_per_item, - 'discount_per_item' => $estimate->discount_per_item, - 'tax' => $estimate->tax, - 'notes' => $estimate->notes, - 'exchange_rate' => $exchange_rate, - 'base_total' => $estimate->total * $exchange_rate, - 'base_discount_val' => $estimate->discount_val * $exchange_rate, - 'base_sub_total' => $estimate->sub_total * $exchange_rate, - 'base_tax' => $estimate->tax * $exchange_rate, - 'base_due_amount' => $estimate->total * $exchange_rate, - 'currency_id' => $estimate->currency_id, - 'sales_tax_type' => $estimate->sales_tax_type, - 'sales_tax_address_type' => $estimate->sales_tax_address_type, - ]); - - $newEstimate->unique_hash = Hashids::connection(Estimate::class)->encode($newEstimate->id); - $newEstimate->save(); - $estimate->load('items.taxes'); - - $estimateItems = $estimate->items->toArray(); - - foreach ($estimateItems as $estimateItem) { - $estimateItem['company_id'] = $request->header('company'); - $estimateItem['name'] = $estimateItem['name']; - $estimateItem['exchange_rate'] = $exchange_rate; - $estimateItem['base_price'] = $estimateItem['price'] * $exchange_rate; - $estimateItem['base_discount_val'] = $estimateItem['discount_val'] * $exchange_rate; - $estimateItem['base_tax'] = $estimateItem['tax'] * $exchange_rate; - $estimateItem['base_total'] = $estimateItem['total'] * $exchange_rate; - - $item = $newEstimate->items()->create($estimateItem); - - if (array_key_exists('taxes', $estimateItem) && $estimateItem['taxes']) { - foreach ($estimateItem['taxes'] as $tax) { - $tax['company_id'] = $request->header('company'); - - if ($tax['amount']) { - $item->taxes()->create($tax); - } - } - } - } - - if ($estimate->taxes) { - foreach ($estimate->taxes->toArray() as $tax) { - $tax['company_id'] = $request->header('company'); - $newEstimate->taxes()->create($tax); - } - } - - if ($estimate->fields()->exists()) { - $customFields = []; - - foreach ($estimate->fields as $data) { - $customFields[] = [ - 'id' => $data->custom_field_id, - 'value' => $data->defaultAnswer, - ]; - } - - $newEstimate->addCustomFields($customFields); - } - - return new EstimateResource($newEstimate); - } -} diff --git a/app/Http/Controllers/V1/Admin/Estimate/ConvertEstimateController.php b/app/Http/Controllers/V1/Admin/Estimate/ConvertEstimateController.php deleted file mode 100644 index eb46f9c3..00000000 --- a/app/Http/Controllers/V1/Admin/Estimate/ConvertEstimateController.php +++ /dev/null @@ -1,133 +0,0 @@ -authorize('create', Invoice::class); - - $estimate->load(['items', 'items.taxes', 'customer', 'taxes']); - - $invoice_date = Carbon::now(); - $due_date = null; - - $dueDateEnabled = CompanySetting::getSetting( - 'invoice_set_due_date_automatically', - $request->header('company') - ); - - if ($dueDateEnabled === 'YES') { - $dueDateDays = intval(CompanySetting::getSetting( - 'invoice_due_date_days', - $request->header('company') - )); - $due_date = Carbon::now()->addDays($dueDateDays)->format('Y-m-d'); - } - - $serial = (new SerialNumberService) - ->setModel($invoice) - ->setCompany($estimate->company_id) - ->setCustomer($estimate->customer_id) - ->setNextNumbers(); - - $templateName = $estimate->getInvoiceTemplateName(); - - $exchange_rate = $estimate->exchange_rate; - - $invoice = Invoice::create([ - 'creator_id' => Auth::id(), - 'invoice_date' => $invoice_date->format('Y-m-d'), - 'due_date' => $due_date, - 'invoice_number' => $serial->getNextNumber(), - 'sequence_number' => $serial->nextSequenceNumber, - 'customer_sequence_number' => $serial->nextCustomerSequenceNumber, - 'reference_number' => $serial->getNextNumber(), - 'customer_id' => $estimate->customer_id, - 'company_id' => $request->header('company'), - 'template_name' => $templateName, - 'status' => Invoice::STATUS_DRAFT, - 'paid_status' => Invoice::STATUS_UNPAID, - 'sub_total' => $estimate->sub_total, - 'discount' => $estimate->discount, - 'discount_type' => $estimate->discount_type, - 'discount_val' => $estimate->discount_val, - 'total' => $estimate->total, - 'due_amount' => $estimate->total, - 'tax_per_item' => $estimate->tax_per_item, - 'discount_per_item' => $estimate->discount_per_item, - 'tax' => $estimate->tax, - 'notes' => $estimate->notes, - 'exchange_rate' => $exchange_rate, - 'base_discount_val' => $estimate->discount_val * $exchange_rate, - 'base_sub_total' => $estimate->sub_total * $exchange_rate, - 'base_total' => $estimate->total * $exchange_rate, - 'base_tax' => $estimate->tax * $exchange_rate, - 'currency_id' => $estimate->currency_id, - 'sales_tax_type' => $estimate->sales_tax_type, - 'sales_tax_address_type' => $estimate->sales_tax_address_type, - ]); - - $invoice->unique_hash = Hashids::connection(Invoice::class)->encode($invoice->id); - $invoice->save(); - $invoiceItems = $estimate->items->toArray(); - - foreach ($invoiceItems as $invoiceItem) { - $invoiceItem['company_id'] = $request->header('company'); - $invoiceItem['name'] = $invoiceItem['name']; - $estimateItem['exchange_rate'] = $exchange_rate; - $estimateItem['base_price'] = $invoiceItem['price'] * $exchange_rate; - $estimateItem['base_discount_val'] = $invoiceItem['discount_val'] * $exchange_rate; - $estimateItem['base_tax'] = $invoiceItem['tax'] * $exchange_rate; - $estimateItem['base_total'] = $invoiceItem['total'] * $exchange_rate; - - $item = $invoice->items()->create($invoiceItem); - - if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) { - foreach ($invoiceItem['taxes'] as $tax) { - $tax['company_id'] = $request->header('company'); - - if ($tax['amount']) { - $item->taxes()->create($tax); - } - } - } - } - - if ($estimate->taxes) { - foreach ($estimate->taxes->toArray() as $tax) { - $tax['company_id'] = $request->header('company'); - $tax['exchange_rate'] = $exchange_rate; - $tax['base_amount'] = $tax['amount'] * $exchange_rate; - $tax['currency_id'] = $estimate->currency_id; - unset($tax['estimate_id']); - - $invoice->taxes()->create($tax); - } - } - - $estimate->checkForEstimateConvertAction(); - - $invoice = Invoice::find($invoice->id); - - return new InvoiceResource($invoice); - } -} diff --git a/app/Http/Controllers/V1/Admin/Estimate/EstimatesController.php b/app/Http/Controllers/V1/Admin/Estimate/EstimatesController.php index 2a9cf6a5..9e40c23a 100644 --- a/app/Http/Controllers/V1/Admin/Estimate/EstimatesController.php +++ b/app/Http/Controllers/V1/Admin/Estimate/EstimatesController.php @@ -5,11 +5,15 @@ namespace App\Http\Controllers\V1\Admin\Estimate; use App\Http\Controllers\Controller; use App\Http\Requests\DeleteEstimatesRequest; use App\Http\Requests\EstimatesRequest; +use App\Http\Requests\SendEstimatesRequest; use App\Http\Resources\EstimateResource; +use App\Http\Resources\InvoiceResource; use App\Jobs\GenerateEstimatePdfJob; use App\Models\Estimate; +use App\Models\Invoice; use App\Services\EstimateService; use Illuminate\Http\Request; +use Illuminate\Mail\Markdown; class EstimatesController extends Controller { @@ -83,4 +87,55 @@ class EstimatesController extends Controller 'success' => true, ]); } + + public function send(SendEstimatesRequest $request, Estimate $estimate) + { + $this->authorize('send estimate', $estimate); + + $response = $this->estimateService->send($estimate, $request->all()); + + return response()->json($response); + } + + public function sendPreview(SendEstimatesRequest $request, Estimate $estimate) + { + $this->authorize('send estimate', $estimate); + + $markdown = new Markdown(view(), config('mail.markdown')); + + $data = $this->estimateService->sendEstimateData($estimate, $request->all()); + $data['url'] = $estimate->estimatePdfUrl; + + return $markdown->render('emails.send.estimate', ['data' => $data]); + } + + public function clone(Request $request, Estimate $estimate) + { + $this->authorize('view', $estimate); + $this->authorize('create', Estimate::class); + + $newEstimate = $this->estimateService->clone($estimate); + + return new EstimateResource($newEstimate); + } + + public function convertToInvoice(Request $request, Estimate $estimate) + { + $this->authorize('create', Invoice::class); + + $invoice = $this->estimateService->convertToInvoice($estimate); + + return new InvoiceResource($invoice); + } + + public function changeStatus(Request $request, Estimate $estimate) + { + $this->authorize('send estimate', $estimate); + + $this->estimateService->changeStatus($estimate, $request->status); + + return response()->json([ + 'success' => true, + ]); + } } diff --git a/app/Http/Controllers/V1/Admin/Estimate/SendEstimateController.php b/app/Http/Controllers/V1/Admin/Estimate/SendEstimateController.php deleted file mode 100644 index 69cb12bb..00000000 --- a/app/Http/Controllers/V1/Admin/Estimate/SendEstimateController.php +++ /dev/null @@ -1,30 +0,0 @@ -authorize('send estimate', $estimate); - - $response = $this->estimateService->send($estimate, $request->all()); - - return response()->json($response); - } -} diff --git a/app/Http/Controllers/V1/Admin/Estimate/SendEstimatePreviewController.php b/app/Http/Controllers/V1/Admin/Estimate/SendEstimatePreviewController.php deleted file mode 100644 index b05327c9..00000000 --- a/app/Http/Controllers/V1/Admin/Estimate/SendEstimatePreviewController.php +++ /dev/null @@ -1,34 +0,0 @@ -authorize('send estimate', $estimate); - - $markdown = new Markdown(view(), config('mail.markdown')); - - $data = $this->estimateService->sendEstimateData($estimate, $request->all()); - $data['url'] = $estimate->estimatePdfUrl; - - return $markdown->render('emails.send.estimate', ['data' => $data]); - } -} diff --git a/app/Http/Controllers/V1/Admin/Invoice/ChangeInvoiceStatusController.php b/app/Http/Controllers/V1/Admin/Invoice/ChangeInvoiceStatusController.php deleted file mode 100644 index 132ff36b..00000000 --- a/app/Http/Controllers/V1/Admin/Invoice/ChangeInvoiceStatusController.php +++ /dev/null @@ -1,36 +0,0 @@ -authorize('send invoice', $invoice); - - if ($request->status == Invoice::STATUS_SENT) { - $invoice->status = Invoice::STATUS_SENT; - $invoice->sent = true; - $invoice->save(); - } elseif ($request->status == Invoice::STATUS_COMPLETED) { - $invoice->status = Invoice::STATUS_COMPLETED; - $invoice->paid_status = Invoice::STATUS_PAID; - $invoice->due_amount = 0; - $invoice->save(); - } - - return response()->json([ - 'success' => true, - ]); - } -} diff --git a/app/Http/Controllers/V1/Admin/Invoice/CloneInvoiceController.php b/app/Http/Controllers/V1/Admin/Invoice/CloneInvoiceController.php deleted file mode 100644 index c23a827c..00000000 --- a/app/Http/Controllers/V1/Admin/Invoice/CloneInvoiceController.php +++ /dev/null @@ -1,144 +0,0 @@ -authorize('view', $invoice); - $this->authorize('create', Invoice::class); - - $date = Carbon::now(); - - $serial = (new SerialNumberService) - ->setModel($invoice) - ->setCompany($invoice->company_id) - ->setCustomer($invoice->customer_id) - ->setNextNumbers(); - - $due_date = null; - $dueDateEnabled = CompanySetting::getSetting( - 'invoice_set_due_date_automatically', - $request->header('company') - ); - - if ($dueDateEnabled === 'YES') { - $dueDateDays = intval(CompanySetting::getSetting( - 'invoice_due_date_days', - $request->header('company') - )); - $due_date = Carbon::now()->addDays($dueDateDays)->format('Y-m-d'); - } - - $exchange_rate = $invoice->exchange_rate; - - $dateFormat = 'Y-m-d'; - $invoiceTimeEnabled = CompanySetting::getSetting( - 'invoice_use_time', - $request->header('company') - ); - - if ($invoiceTimeEnabled === 'YES') { - $dateFormat .= ' H:i'; - } - - $newInvoice = Invoice::create([ - 'invoice_date' => $date->format('Y-m-d'), - 'due_date' => $due_date, - 'invoice_number' => $serial->getNextNumber(), - 'sequence_number' => $serial->nextSequenceNumber, - 'customer_sequence_number' => $serial->nextCustomerSequenceNumber, - 'reference_number' => $invoice->reference_number, - 'customer_id' => $invoice->customer_id, - 'company_id' => $request->header('company'), - 'template_name' => $invoice->template_name, - 'status' => Invoice::STATUS_DRAFT, - 'paid_status' => Invoice::STATUS_UNPAID, - 'sub_total' => $invoice->sub_total, - 'discount' => $invoice->discount, - 'discount_type' => $invoice->discount_type, - 'discount_val' => $invoice->discount_val, - 'total' => $invoice->total, - 'due_amount' => $invoice->total, - 'tax_per_item' => $invoice->tax_per_item, - 'discount_per_item' => $invoice->discount_per_item, - 'tax' => $invoice->tax, - 'notes' => $invoice->notes, - 'exchange_rate' => $exchange_rate, - 'base_total' => $invoice->total * $exchange_rate, - 'base_discount_val' => $invoice->discount_val * $exchange_rate, - 'base_sub_total' => $invoice->sub_total * $exchange_rate, - 'base_tax' => $invoice->tax * $exchange_rate, - 'base_due_amount' => $invoice->total * $exchange_rate, - 'currency_id' => $invoice->currency_id, - 'sales_tax_type' => $invoice->sales_tax_type, - 'sales_tax_address_type' => $invoice->sales_tax_address_type, - ]); - - $newInvoice->unique_hash = Hashids::connection(Invoice::class)->encode($newInvoice->id); - $newInvoice->save(); - $invoice->load('items.taxes'); - - $invoiceItems = $invoice->items->toArray(); - - foreach ($invoiceItems as $invoiceItem) { - $invoiceItem['company_id'] = $request->header('company'); - $invoiceItem['name'] = $invoiceItem['name']; - $invoiceItem['exchange_rate'] = $exchange_rate; - $invoiceItem['base_price'] = $invoiceItem['price'] * $exchange_rate; - $invoiceItem['base_discount_val'] = $invoiceItem['discount_val'] * $exchange_rate; - $invoiceItem['base_tax'] = $invoiceItem['tax'] * $exchange_rate; - $invoiceItem['base_total'] = $invoiceItem['total'] * $exchange_rate; - - $item = $newInvoice->items()->create($invoiceItem); - - if (array_key_exists('taxes', $invoiceItem) && $invoiceItem['taxes']) { - foreach ($invoiceItem['taxes'] as $tax) { - $tax['company_id'] = $request->header('company'); - - if ($tax['amount']) { - $item->taxes()->create($tax); - } - } - } - } - - if ($invoice->taxes) { - foreach ($invoice->taxes->toArray() as $tax) { - $tax['company_id'] = $request->header('company'); - $newInvoice->taxes()->create($tax); - } - } - - if ($invoice->fields()->exists()) { - $customFields = []; - - foreach ($invoice->fields as $data) { - $customFields[] = [ - 'id' => $data->custom_field_id, - 'value' => $data->defaultAnswer, - ]; - } - - $newInvoice->addCustomFields($customFields); - } - - return new InvoiceResource($newInvoice); - } -} diff --git a/app/Http/Controllers/V1/Admin/Invoice/InvoicesController.php b/app/Http/Controllers/V1/Admin/Invoice/InvoicesController.php index e95078fb..2ccad148 100644 --- a/app/Http/Controllers/V1/Admin/Invoice/InvoicesController.php +++ b/app/Http/Controllers/V1/Admin/Invoice/InvoicesController.php @@ -5,12 +5,14 @@ namespace App\Http\Controllers\V1\Admin\Invoice; use App\Http\Controllers\Controller; use App\Http\Requests; use App\Http\Requests\DeleteInvoiceRequest; +use App\Http\Requests\SendInvoiceRequest; use App\Http\Resources\InvoiceResource; use App\Jobs\GenerateInvoicePdfJob; use App\Models\Invoice; use App\Services\InvoiceService; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use Illuminate\Mail\Markdown; class InvoicesController extends Controller { @@ -111,4 +113,48 @@ class InvoicesController extends Controller 'success' => true, ]); } + + public function send(SendInvoiceRequest $request, Invoice $invoice) + { + $this->authorize('send invoice', $invoice); + + $this->invoiceService->send($invoice, $request->all()); + + return response()->json([ + 'success' => true, + ]); + } + + public function sendPreview(SendInvoiceRequest $request, Invoice $invoice) + { + $this->authorize('send invoice', $invoice); + + $markdown = new Markdown(view(), config('mail.markdown')); + + $data = $this->invoiceService->sendInvoiceData($invoice, $request->all()); + $data['url'] = $invoice->invoicePdfUrl; + + return $markdown->render('emails.send.invoice', ['data' => $data]); + } + + public function clone(Request $request, Invoice $invoice) + { + $this->authorize('view', $invoice); + $this->authorize('create', Invoice::class); + + $newInvoice = $this->invoiceService->clone($invoice); + + return new InvoiceResource($newInvoice); + } + + public function changeStatus(Request $request, Invoice $invoice) + { + $this->authorize('send invoice', $invoice); + + $this->invoiceService->changeStatus($invoice, $request->status); + + return response()->json([ + 'success' => true, + ]); + } } diff --git a/app/Http/Controllers/V1/Admin/Invoice/SendInvoiceController.php b/app/Http/Controllers/V1/Admin/Invoice/SendInvoiceController.php deleted file mode 100644 index a26d5e70..00000000 --- a/app/Http/Controllers/V1/Admin/Invoice/SendInvoiceController.php +++ /dev/null @@ -1,34 +0,0 @@ -authorize('send invoice', $invoice); - - $this->invoiceService->send($invoice, $request->all()); - - return response()->json([ - 'success' => true, - ]); - } -} diff --git a/app/Http/Controllers/V1/Admin/Invoice/SendInvoicePreviewController.php b/app/Http/Controllers/V1/Admin/Invoice/SendInvoicePreviewController.php deleted file mode 100644 index e4eac342..00000000 --- a/app/Http/Controllers/V1/Admin/Invoice/SendInvoicePreviewController.php +++ /dev/null @@ -1,36 +0,0 @@ -authorize('send invoice', $invoice); - - $markdown = new Markdown(view(), config('mail.markdown')); - - $data = $this->invoiceService->sendInvoiceData($invoice, $request->all()); - $data['url'] = $invoice->invoicePdfUrl; - - return $markdown->render('emails.send.invoice', ['data' => $data]); - } -} diff --git a/app/Http/Controllers/V1/Admin/Payment/PaymentsController.php b/app/Http/Controllers/V1/Admin/Payment/PaymentsController.php index 5aaeb461..2eab09f8 100644 --- a/app/Http/Controllers/V1/Admin/Payment/PaymentsController.php +++ b/app/Http/Controllers/V1/Admin/Payment/PaymentsController.php @@ -5,11 +5,13 @@ namespace App\Http\Controllers\V1\Admin\Payment; use App\Http\Controllers\Controller; use App\Http\Requests\DeletePaymentsRequest; use App\Http\Requests\PaymentRequest; +use App\Http\Requests\SendPaymentRequest; use App\Http\Resources\PaymentResource; use App\Models\Payment; use App\Services\PaymentService; use Illuminate\Http\Request; use Illuminate\Http\Response; +use Illuminate\Mail\Markdown; class PaymentsController extends Controller { @@ -88,4 +90,25 @@ class PaymentsController extends Controller 'success' => true, ]); } + + public function send(SendPaymentRequest $request, Payment $payment) + { + $this->authorize('send payment', $payment); + + $response = $this->paymentService->send($payment, $request->all()); + + return response()->json($response); + } + + public function sendPreview(Request $request, Payment $payment) + { + $this->authorize('send payment', $payment); + + $markdown = new Markdown(view(), config('mail.markdown')); + + $data = $this->paymentService->sendPaymentData($payment, $request->all()); + $data['url'] = $payment->paymentPdfUrl; + + return $markdown->render('emails.send.payment', ['data' => $data]); + } } diff --git a/app/Http/Controllers/V1/Admin/Payment/SendPaymentController.php b/app/Http/Controllers/V1/Admin/Payment/SendPaymentController.php deleted file mode 100644 index e9db7617..00000000 --- a/app/Http/Controllers/V1/Admin/Payment/SendPaymentController.php +++ /dev/null @@ -1,32 +0,0 @@ -authorize('send payment', $payment); - - $response = $this->paymentService->send($payment, $request->all()); - - return response()->json($response); - } -} diff --git a/app/Http/Controllers/V1/Admin/Payment/SendPaymentPreviewController.php b/app/Http/Controllers/V1/Admin/Payment/SendPaymentPreviewController.php deleted file mode 100644 index 6fcd3832..00000000 --- a/app/Http/Controllers/V1/Admin/Payment/SendPaymentPreviewController.php +++ /dev/null @@ -1,34 +0,0 @@ -authorize('send payment', $payment); - - $markdown = new Markdown(view(), config('mail.markdown')); - - $data = $this->paymentService->sendPaymentData($payment, $request->all()); - $data['url'] = $payment->paymentPdfUrl; - - return $markdown->render('emails.send.payment', ['data' => $data]); - } -} diff --git a/app/Services/EstimateService.php b/app/Services/EstimateService.php index 56e08ed0..e6d97fe2 100644 --- a/app/Services/EstimateService.php +++ b/app/Services/EstimateService.php @@ -11,8 +11,11 @@ use App\Models\CompanySetting; use App\Models\CustomField; use App\Models\Estimate; use App\Models\ExchangeRateLog; +use App\Models\Invoice; use App\Services\Pdf\PdfTemplateUtils; +use Carbon\Carbon; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Auth; class EstimateService { @@ -199,4 +202,169 @@ class EstimateService return Pdf::loadView($templatePath); } + + public function clone(Estimate $estimate): Estimate + { + $date = Carbon::now(); + + $serial = (new SerialNumberService) + ->setModel($estimate) + ->setCompany($estimate->company_id) + ->setCustomer($estimate->customer_id) + ->setNextNumbers(); + + $expiryDate = null; + $expiryEnabled = CompanySetting::getSetting( + 'estimate_set_expiry_date_automatically', + $estimate->company_id + ); + + if ($expiryEnabled === 'YES') { + $expiryDays = intval(CompanySetting::getSetting( + 'estimate_expiry_date_days', + $estimate->company_id + )); + $expiryDate = Carbon::now()->addDays($expiryDays)->format('Y-m-d'); + } + + $exchangeRate = $estimate->exchange_rate; + + $newEstimate = Estimate::create([ + 'estimate_date' => $date->format('Y-m-d'), + 'expiry_date' => $expiryDate, + 'estimate_number' => $serial->getNextNumber(), + 'sequence_number' => $serial->nextSequenceNumber, + 'customer_sequence_number' => $serial->nextCustomerSequenceNumber, + 'reference_number' => $estimate->reference_number, + 'customer_id' => $estimate->customer_id, + 'company_id' => $estimate->company_id, + 'template_name' => $estimate->template_name, + 'status' => Estimate::STATUS_DRAFT, + 'sub_total' => $estimate->sub_total, + 'discount' => $estimate->discount, + 'discount_type' => $estimate->discount_type, + 'discount_val' => $estimate->discount_val, + 'total' => $estimate->total, + 'due_amount' => $estimate->total, + 'tax_per_item' => $estimate->tax_per_item, + 'discount_per_item' => $estimate->discount_per_item, + 'tax' => $estimate->tax, + 'notes' => $estimate->notes, + 'exchange_rate' => $exchangeRate, + 'base_total' => $estimate->total * $exchangeRate, + 'base_discount_val' => $estimate->discount_val * $exchangeRate, + 'base_sub_total' => $estimate->sub_total * $exchangeRate, + 'base_tax' => $estimate->tax * $exchangeRate, + 'base_due_amount' => $estimate->total * $exchangeRate, + 'currency_id' => $estimate->currency_id, + 'sales_tax_type' => $estimate->sales_tax_type, + 'sales_tax_address_type' => $estimate->sales_tax_address_type, + ]); + + $newEstimate->unique_hash = Hashids::connection(Estimate::class)->encode($newEstimate->id); + $newEstimate->save(); + + $estimate->load('items.taxes'); + $this->documentItemService->createItems($newEstimate, $estimate->items->toArray()); + + if ($estimate->taxes) { + $this->documentItemService->createTaxes($newEstimate, $estimate->taxes->toArray()); + } + + if ($estimate->fields()->exists()) { + $customFields = []; + + foreach ($estimate->fields as $data) { + $customFields[] = [ + 'id' => $data->custom_field_id, + 'value' => $data->defaultAnswer, + ]; + } + + $newEstimate->addCustomFields($customFields); + } + + return $newEstimate; + } + + public function convertToInvoice(Estimate $estimate): Invoice + { + $estimate->load(['items', 'items.taxes', 'customer', 'taxes']); + + $invoiceDate = Carbon::now(); + $dueDate = null; + + $dueDateEnabled = CompanySetting::getSetting( + 'invoice_set_due_date_automatically', + $estimate->company_id + ); + + if ($dueDateEnabled === 'YES') { + $dueDateDays = intval(CompanySetting::getSetting( + 'invoice_due_date_days', + $estimate->company_id + )); + $dueDate = Carbon::now()->addDays($dueDateDays)->format('Y-m-d'); + } + + $serial = (new SerialNumberService) + ->setModel(new Invoice) + ->setCompany($estimate->company_id) + ->setCustomer($estimate->customer_id) + ->setNextNumbers(); + + $templateName = $estimate->getInvoiceTemplateName(); + $exchangeRate = $estimate->exchange_rate; + + $invoice = Invoice::create([ + 'creator_id' => Auth::id(), + 'invoice_date' => $invoiceDate->format('Y-m-d'), + 'due_date' => $dueDate, + 'invoice_number' => $serial->getNextNumber(), + 'sequence_number' => $serial->nextSequenceNumber, + 'customer_sequence_number' => $serial->nextCustomerSequenceNumber, + 'reference_number' => $serial->getNextNumber(), + 'customer_id' => $estimate->customer_id, + 'company_id' => $estimate->company_id, + 'template_name' => $templateName, + 'status' => Invoice::STATUS_DRAFT, + 'paid_status' => Invoice::STATUS_UNPAID, + 'sub_total' => $estimate->sub_total, + 'discount' => $estimate->discount, + 'discount_type' => $estimate->discount_type, + 'discount_val' => $estimate->discount_val, + 'total' => $estimate->total, + 'due_amount' => $estimate->total, + 'tax_per_item' => $estimate->tax_per_item, + 'discount_per_item' => $estimate->discount_per_item, + 'tax' => $estimate->tax, + 'notes' => $estimate->notes, + 'exchange_rate' => $exchangeRate, + 'base_discount_val' => $estimate->discount_val * $exchangeRate, + 'base_sub_total' => $estimate->sub_total * $exchangeRate, + 'base_total' => $estimate->total * $exchangeRate, + 'base_tax' => $estimate->tax * $exchangeRate, + 'currency_id' => $estimate->currency_id, + 'sales_tax_type' => $estimate->sales_tax_type, + 'sales_tax_address_type' => $estimate->sales_tax_address_type, + ]); + + $invoice->unique_hash = Hashids::connection(Invoice::class)->encode($invoice->id); + $invoice->save(); + + $this->documentItemService->createItems($invoice, $estimate->items->toArray()); + + if ($estimate->taxes) { + $this->documentItemService->createTaxes($invoice, $estimate->taxes->toArray()); + } + + $estimate->checkForEstimateConvertAction(); + + return Invoice::find($invoice->id); + } + + public function changeStatus(Estimate $estimate, string $status): void + { + $estimate->update(['status' => $status]); + } } diff --git a/app/Services/InvoiceService.php b/app/Services/InvoiceService.php index e2223740..fae21c4c 100644 --- a/app/Services/InvoiceService.php +++ b/app/Services/InvoiceService.php @@ -12,6 +12,7 @@ use App\Models\CustomField; use App\Models\ExchangeRateLog; use App\Models\Invoice; use App\Services\Pdf\PdfTemplateUtils; +use Carbon\Carbon; use Illuminate\Http\Request; use Illuminate\Support\Collection; use Illuminate\Validation\ValidationException; @@ -264,4 +265,103 @@ class InvoiceService return Pdf::loadView($templatePath); } + + public function clone(Invoice $invoice): Invoice + { + $date = Carbon::now(); + + $serial = (new SerialNumberService) + ->setModel($invoice) + ->setCompany($invoice->company_id) + ->setCustomer($invoice->customer_id) + ->setNextNumbers(); + + $dueDate = null; + $dueDateEnabled = CompanySetting::getSetting( + 'invoice_set_due_date_automatically', + $invoice->company_id + ); + + if ($dueDateEnabled === 'YES') { + $dueDateDays = intval(CompanySetting::getSetting( + 'invoice_due_date_days', + $invoice->company_id + )); + $dueDate = Carbon::now()->addDays($dueDateDays)->format('Y-m-d'); + } + + $exchangeRate = $invoice->exchange_rate; + + $newInvoice = Invoice::create([ + 'invoice_date' => $date->format('Y-m-d'), + 'due_date' => $dueDate, + 'invoice_number' => $serial->getNextNumber(), + 'sequence_number' => $serial->nextSequenceNumber, + 'customer_sequence_number' => $serial->nextCustomerSequenceNumber, + 'reference_number' => $invoice->reference_number, + 'customer_id' => $invoice->customer_id, + 'company_id' => $invoice->company_id, + 'template_name' => $invoice->template_name, + 'status' => Invoice::STATUS_DRAFT, + 'paid_status' => Invoice::STATUS_UNPAID, + 'sub_total' => $invoice->sub_total, + 'discount' => $invoice->discount, + 'discount_type' => $invoice->discount_type, + 'discount_val' => $invoice->discount_val, + 'total' => $invoice->total, + 'due_amount' => $invoice->total, + 'tax_per_item' => $invoice->tax_per_item, + 'discount_per_item' => $invoice->discount_per_item, + 'tax' => $invoice->tax, + 'notes' => $invoice->notes, + 'exchange_rate' => $exchangeRate, + 'base_total' => $invoice->total * $exchangeRate, + 'base_discount_val' => $invoice->discount_val * $exchangeRate, + 'base_sub_total' => $invoice->sub_total * $exchangeRate, + 'base_tax' => $invoice->tax * $exchangeRate, + 'base_due_amount' => $invoice->total * $exchangeRate, + 'currency_id' => $invoice->currency_id, + 'sales_tax_type' => $invoice->sales_tax_type, + 'sales_tax_address_type' => $invoice->sales_tax_address_type, + ]); + + $newInvoice->unique_hash = Hashids::connection(Invoice::class)->encode($newInvoice->id); + $newInvoice->save(); + + $invoice->load('items.taxes'); + $this->documentItemService->createItems($newInvoice, $invoice->items->toArray()); + + if ($invoice->taxes) { + $this->documentItemService->createTaxes($newInvoice, $invoice->taxes->toArray()); + } + + if ($invoice->fields()->exists()) { + $customFields = []; + + foreach ($invoice->fields as $data) { + $customFields[] = [ + 'id' => $data->custom_field_id, + 'value' => $data->defaultAnswer, + ]; + } + + $newInvoice->addCustomFields($customFields); + } + + return $newInvoice; + } + + public function changeStatus(Invoice $invoice, string $status): void + { + if ($status == Invoice::STATUS_SENT) { + $invoice->status = Invoice::STATUS_SENT; + $invoice->sent = true; + $invoice->save(); + } elseif ($status == Invoice::STATUS_COMPLETED) { + $invoice->status = Invoice::STATUS_COMPLETED; + $invoice->paid_status = Invoice::STATUS_PAID; + $invoice->due_amount = 0; + $invoice->save(); + } + } } diff --git a/routes/api.php b/routes/api.php index a82b0a0e..043d90e5 100644 --- a/routes/api.php +++ b/routes/api.php @@ -8,13 +8,8 @@ use App\Http\Controllers\V1\Admin\Customer\CustomersController; use App\Http\Controllers\V1\Admin\Customer\CustomerStatsController; use App\Http\Controllers\V1\Admin\CustomField\CustomFieldsController; use App\Http\Controllers\V1\Admin\Dashboard\DashboardController; -use App\Http\Controllers\V1\Admin\Estimate\ChangeEstimateStatusController; -use App\Http\Controllers\V1\Admin\Estimate\CloneEstimateController; -use App\Http\Controllers\V1\Admin\Estimate\ConvertEstimateController; use App\Http\Controllers\V1\Admin\Estimate\EstimatesController; use App\Http\Controllers\V1\Admin\Estimate\EstimateTemplatesController; -use App\Http\Controllers\V1\Admin\Estimate\SendEstimateController; -use App\Http\Controllers\V1\Admin\Estimate\SendEstimatePreviewController; use App\Http\Controllers\V1\Admin\ExchangeRate\ExchangeRateProviderController; use App\Http\Controllers\V1\Admin\ExchangeRate\GetActiveProviderController; use App\Http\Controllers\V1\Admin\ExchangeRate\GetExchangeRateController; @@ -38,19 +33,13 @@ use App\Http\Controllers\V1\Admin\General\SearchController; use App\Http\Controllers\V1\Admin\General\SearchUsersController; use App\Http\Controllers\V1\Admin\General\TimeFormatsController; use App\Http\Controllers\V1\Admin\General\TimezonesController; -use App\Http\Controllers\V1\Admin\Invoice\ChangeInvoiceStatusController; -use App\Http\Controllers\V1\Admin\Invoice\CloneInvoiceController; use App\Http\Controllers\V1\Admin\Invoice\InvoicesController; use App\Http\Controllers\V1\Admin\Invoice\InvoiceTemplatesController; -use App\Http\Controllers\V1\Admin\Invoice\SendInvoiceController; -use App\Http\Controllers\V1\Admin\Invoice\SendInvoicePreviewController; use App\Http\Controllers\V1\Admin\Item\ItemsController; use App\Http\Controllers\V1\Admin\Item\UnitsController; use App\Http\Controllers\V1\Admin\Mobile\AuthController; use App\Http\Controllers\V1\Admin\Payment\PaymentMethodsController; use App\Http\Controllers\V1\Admin\Payment\PaymentsController; -use App\Http\Controllers\V1\Admin\Payment\SendPaymentController; -use App\Http\Controllers\V1\Admin\Payment\SendPaymentPreviewController; use App\Http\Controllers\V1\Admin\RecurringInvoice\RecurringInvoiceController; use App\Http\Controllers\V1\Admin\RecurringInvoice\RecurringInvoiceFrequencyController; use App\Http\Controllers\V1\Admin\Role\AbilitiesController; @@ -278,13 +267,13 @@ Route::prefix('/v1')->group(function () { // Invoices // ------------------------------------------------- - Route::get('/invoices/{invoice}/send/preview', SendInvoicePreviewController::class); + Route::get('/invoices/{invoice}/send/preview', [InvoicesController::class, 'sendPreview']); - Route::post('/invoices/{invoice}/send', SendInvoiceController::class); + Route::post('/invoices/{invoice}/send', [InvoicesController::class, 'send']); - Route::post('/invoices/{invoice}/clone', CloneInvoiceController::class); + Route::post('/invoices/{invoice}/clone', [InvoicesController::class, 'clone']); - Route::post('/invoices/{invoice}/status', ChangeInvoiceStatusController::class); + Route::post('/invoices/{invoice}/status', [InvoicesController::class, 'changeStatus']); Route::post('/invoices/delete', [InvoicesController::class, 'delete']); @@ -304,15 +293,15 @@ Route::prefix('/v1')->group(function () { // Estimates // ------------------------------------------------- - Route::get('/estimates/{estimate}/send/preview', SendEstimatePreviewController::class); + Route::get('/estimates/{estimate}/send/preview', [EstimatesController::class, 'sendPreview']); - Route::post('/estimates/{estimate}/send', SendEstimateController::class); + Route::post('/estimates/{estimate}/send', [EstimatesController::class, 'send']); - Route::post('/estimates/{estimate}/clone', CloneEstimateController::class); + Route::post('/estimates/{estimate}/clone', [EstimatesController::class, 'clone']); - Route::post('/estimates/{estimate}/status', ChangeEstimateStatusController::class); + Route::post('/estimates/{estimate}/status', [EstimatesController::class, 'changeStatus']); - Route::post('/estimates/{estimate}/convert-to-invoice', ConvertEstimateController::class); + Route::post('/estimates/{estimate}/convert-to-invoice', [EstimatesController::class, 'convertToInvoice']); Route::get('/estimates/templates', EstimateTemplatesController::class); @@ -336,9 +325,9 @@ Route::prefix('/v1')->group(function () { // Payments // ---------------------------------- - Route::get('/payments/{payment}/send/preview', SendPaymentPreviewController::class); + Route::get('/payments/{payment}/send/preview', [PaymentsController::class, 'sendPreview']); - Route::post('/payments/{payment}/send', SendPaymentController::class); + Route::post('/payments/{payment}/send', [PaymentsController::class, 'send']); Route::post('/payments/delete', [PaymentsController::class, 'delete']); diff --git a/tests/Feature/Admin/EstimateTest.php b/tests/Feature/Admin/EstimateTest.php index d8efc183..f0c505ad 100644 --- a/tests/Feature/Admin/EstimateTest.php +++ b/tests/Feature/Admin/EstimateTest.php @@ -1,7 +1,6 @@ assertActionUsesFormRequest( - SendEstimateController::class, - '__invoke', + EstimatesController::class, + 'send', SendEstimatesRequest::class ); });