Compare commits

...

3 Commits

Author SHA1 Message Date
Dillon bf38ace70c Multiple invoices into one 2023-01-07 11:51:27 +08:00
edmondlang 851e2e1815 multi payment ui 2022-12-24 16:39:17 +08:00
edmondlang 503bc90556 multiple payment ui 2022-12-23 16:37:06 +08:00
13 changed files with 643 additions and 6 deletions
@@ -0,0 +1,20 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use Illuminate\Database\Eloquent\Builder;
class Receiver implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->where('receiver', '=', $value);
}
}
@@ -0,0 +1,66 @@
<?php
namespace App\Classes\Modules\Companies\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Transactions\Services\ListsTransactions;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Http\Resources\TransactionResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ListCompanyModuleInvoicesLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification(): array
{
return [
'title' => 'Retrieved Company Module Invoices',
'message' => 'You have successfully retrieved a list of Invoices'
];
}
/** @var ListsTransactions */
private $listsTransactions;
/**
* ListCompanyModuleInvoicesLogic constructor.
* @param ListsTransactions $listsTransactions
*/
public function __construct(ListsTransactions $listsTransactions)
{
$this->listsTransactions = $listsTransactions;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\AccessForbiddenException
* @throws \App\Classes\Exceptions\MalformedRequestException
* @throws \App\Classes\Exceptions\RequestValidationException
*/
public function logic(Request $request): JsonResponse
{
$filterArray = [
"per_page" => 10,
"order_by" => (object)[
"column" => 'id',
"DESC" => true,
],
"status_in" => [2],
"receiver" => intval($request->route('company_module_id')),
"type" => TransactionType::SHIPPING_INVOICE
];
// $this->canListTransactions->passes();
$query = $this->listsTransactions->execute($filterArray);
return $this->collectionResponse(TransactionResource::collection($query));
}
}
@@ -0,0 +1,104 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\Notifications\InvoiceIssuedEmail;
use Illuminate\Http\Request;
use Illuminate\Http\JsonResponse;
use Meneses\LaravelMpdf\Facades\LaravelMpdf;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\PackingLists\Services\FetchesPackingList;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\Modules\Transactions\ControllersLogic\Document;
class CreateCombinedInvoicesLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification():array {
return [
'title' => 'Shipping Invoice Status',
'message' => 'You have successfully updated multiple shipping invoices status'
];
}
/** @var FetchesPackingList */
private $fetchesPackingList;
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFiles;
/**
* ApprovePaymentVerificationLogic constructor.
* @param FetchesPackingList $fetchesPackingList
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFiles
* @param CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor
*/
public function __construct(FetchesPackingList $fetchesPackingList, UpdatesTransactionStatus $updatesTransactionStatus, CreatesDocument $createsDocument, CreatesFiles $createsFiles)
{
$this->fetchesPackingList = $fetchesPackingList;
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->createsDocument = $createsDocument;
$this->createsFiles = $createsFiles;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function logic(Request $request) : JsonResponse
{
$items = $request->input('ids');
$invoice_transactions=array();
foreach($items as $item){
$packing_list = $this->fetchesPackingList->execute(['id' => $item['id']]);
$invoice_transaction = $packing_list->transactions()->where('transactions.type', TransactionType::SHIPPING_INVOICE)->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::PENDING_SUBMISSION])->first();
array_push($invoice_transactions, $invoice_transaction);
// $this->updatesTransactionStatus->execute($invoice_transaction, ApprovalStatus::APPROVED);
}
$transaction_invoice_pdf = LaravelMpdf::loadView('pages.pdfs.shipping_invoices_combined', ['invoice_transactions' => $invoice_transactions]);
$document_object = new DocumentObject(
DocumentType::SHIPPING_INVOICE,
[chunk_split('data:application/pdf;base64,'.base64_encode($transaction_invoice_pdf->output()))],
'',
ApprovalStatus::COMPLETED,
'shipping_invoice'
);
/** @var Document $document */
$document = $this->createsDocument->execute($invoice_transaction, $document_object);
$this->createsFiles->execute($document, $document_object);
$user = $packing_list->owner->companyModule->employees()->first();
if(app()->environment(['production'])) {
$user->notify(new InvoiceIssuedEmail($user, $packing_list));
}
return $this->response([]);
}
}
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Companies;
use App\Classes\Modules\Companies\ControllersLogic\ListCompanyModuleInvoicesLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class ListCompanyModuleInvoicesController
{
/**
* @param Request $request
* @param ListCompanyModulesLogic $logic
* @return JsonResponse
*/
public function list(Request $request, ListCompanyModuleInvoicesLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,15 @@
<?php
namespace App\Http\Controllers\Transactions;
use App\Classes\Modules\Transactions\ControllersLogic\CreateCombinedInvoicesLogic;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
class CreateCombinedInvoicesController
{
public function combine(Request $request, CreateCombinedInvoicesLogic $logic): JsonResponse {
return $logic->execute($request);
}
}
@@ -0,0 +1,175 @@
<template>
<div class="row">
<div class="col">
<div class="row">
<div class="col-12 col-sm-12 col-md-9">
<div class="row m-b-15 m-l-5 m-r-10">
<div class="col b-a b-grey rounded bg-master-light">
<div class="row">
<div class="col padding-20">
<div class="row align-items-center justify-conten-center">
<div class="col-auto pointer">
<i class="fa fs-30 fa-fw fa-square-o"></i>
</div>
<div class="col">
<h5 class="no-margin font-heading">Invoice No</h5>
</div>
<div class="col">
<h5 class="no-margin">Invoice Date</h5>
</div>
<div class="col">
<h5 class="no-margin">Status</h5>
</div>
<div class="col">
<h5 class="no-margin">Amount</h5>
</div>
<div class="col-auto invisible">
<div class="btn btn-default no-border">
<i class="fa fa-angle-up"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- <list-component section="containerListSection" :endpoint="route('api.address.district.list')">
<template slot="list" slot-scope="{data}">
<payments-billing-components :data="data"></payments-billing-components>
</template>
</list-component> -->
<payments-billing-components :data="invoice" v-for="invoice in invoices"></payments-billing-components>
<!-- <div class="row" v-for="invoice in invoices">
<div class="col">
{{ invoice.id }}
</div>
</div> -->
</div>
<div class="col-12 col-sm-12 col-md-3">
<div class="row align-items-center">
<div class="col b-a b-grey rounded padding-25">
<div class="row">
<div class="col">
<h6 class="semi-bold muted">Payment Summary</h6>
</div>
</div>
<div class="row align-items-center justify-content-center">
<div class="col-auto">
<div class="padding-5">
<i class="fa fa-angle-up"></i>
</div>
</div>
<div class="col p-l-0">
<h6 class="semi-bold text-primary">2 Invoice Selected</h6>
</div>
</div>
<div class="row">
<div class="col">
<div class="row">
<div class="col-auto">
<h6 class="no-margin">x1</h6>
</div>
<div class="col">
<h6 class="no-margin">lorem ipsum</h6>
</div>
<div class="col-auto">
<h6 class="no-margin">52x62x635 CM</h6>
</div>
</div>
<div class="row">
<div class="col-auto">
<h6 class="no-margin">x1</h6>
</div>
<div class="col">
<h6 class="no-margin">lorem ipsum</h6>
</div>
<div class="col-auto">
<h6 class="no-margin">52x62x635 CM</h6>
</div>
</div>
</div>
</div>
<hr>
<div class="row">
<div class="col">
<h6 class="normal m-t-5 m-b-5">Shipping Fee</h6>
</div>
<div class="col-auto">
<h6 class="normal m-t-5 m-b-5">RM 212.15</h6>
</div>
</div>
<div class="row">
<div class="col">
<h6 class="normal m-t-5 m-b-5">Serrvice Fee</h6>
</div>
<div class="col-auto">
<h6 class="normal m-t-5 m-b-5">RM 41.25</h6>
</div>
</div>
<div class="row">
<div class="col">
<h6 class="normal m-t-5 m-b-5">Discount</h6>
</div>
<div class="col-auto">
<h6 class="normal m-t-5 m-b-5">RM 0.00</h6>
</div>
</div>
<hr>
<div class="row">
<div class="col">
<h6 class="normal">Total Payments</h6>
</div>
<div class="col-auto">
<h6 class="text-primary bold">RM 3300.00</h6>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
company_module_id: {
type: Number,
required: true,
}
},
data(){
return {
section: 'customerPaymentBillingSectionComponent',
isLoading: true,
invoices: null
}
},
computed: {
pendingQueue () {
return this.$store.getters.isInCompleteQueue(this.section);
}
},
watch: {
pendingQueue(inComplete){
if(inComplete){
this.fetchInvoice();
}
}
},
created(){
this.$store.dispatch('updateListQueue', {'name': this.section});
},
methods: {
fetchInvoice(){
this.isLoading = true;
this.submit(route('api.company.invoice.list', this.company_module_id), 'get', this.section, false, false)
},
successHandler(response){
this.$store.dispatch('completeList', {'name': this.section, 'data': []});
this.isLoading = false;
this.invoices = response.payload.data;
}
}
}
</script>
@@ -8,7 +8,7 @@
<i class="fa fs-30 fa-fw" :class="{'fa-square-o': !selected, 'fa-check-square': selected, 'text-primary':selected}" ></i>
</div>
<div class="col">
<h5 class="no-margin">{{item.country.id}}05052021</h5>
<h5 class="no-margin">05052021</h5>
</div>
<div class="col">
<h5 class="no-margin">Invoice Date Invoice Date</h5>
@@ -0,0 +1,4 @@
@extends('layouts.base_portal')
@section('inner_content')
<customer-payment-billing-section-component :company_module_id={{$company_module_id}}></customer-payment-billing-section-component>
@endsection
@@ -0,0 +1,220 @@
@extends('layouts.base_pdf')
@section('inner_content')
@php
$grandTotal = 0;
$grandSubTotal = 0;
@endphp
<br>
<br>
<table class="line-table" style="overflow: wrap" autosize="1">
<thead>
<tr>
<th width="5%">No</th>
<th class="description">Description</th>
<th width="15%">Quantity</th>
<th width="20%">Unit Price (RM)</th>
<th width="20%">Total Amount<br>(RM)</th>
</tr>
</thead>
<tbody>
@foreach ($invoice_transactions as $invoice_transaction)
@foreach ($invoice_transaction->transactionDetails as $key => $transaction_detail)
<tr>
<td width="5%" class="center top">{{ $key + 1 }}</td>
<td class="description">{!! $transaction_detail->name !!}</td>
<td width="15%" class="center top" style="text-align: center">{{ round($transaction_detail->quantity, 3) }}</td>
<td width="20%" class="center top" style="text-align: center">
{{ round($transaction_detail->price, 2) }}
</td>
<td width="20%" class="right top">
{{ round($transaction_detail->amount, 2) }}
</td>
</tr>
@php
$grandSubTotal = $grandSubTotal + $invoice_transaction->amount;
$grandTotal = $grandTotal + $invoice_transaction->amount;
@endphp
@endforeach
@endforeach
</tbody>
<tfoot>
<tr class="subtotal">
<td colspan="3"></td>
<td class="right middle">Subtotal</td>
<td class="right middle">
{{ round($grandSubTotal, 2) }}
</td>
</tr>
<!-- <tr class="billingcharges">
<td colspan="3"></td>
<td class="right">Service Charges</td>
<td class="right">
{{ round($invoice_transaction->service_charge, 2) }}
</td>
</tr>
@if($invoice_transaction->tax > 0)
<tr class="billingcharges">
<td colspan="3"></td>
<td class="right">Tax</td>
<td class="right">{{ number_format($invoice_transaction->tax, 2) }}</td>
</tr>
@endif -->
<tr>
<td colspan="3"></td>
<td class="right middle">Total</td>
<td class="total right middle">
{{ round($grandTotal, 2) }}
</td>
</tr>
</tfoot>
</table>
@foreach ($invoice_transactions as $invoice_transaction)
<br>
<htmlpageheader name="page-header">
<br><br>
<div class="separator"><strong><i>{{ $invoice_transaction->bill_no }}</i></strong></div>
</htmlpageheader>
<table>
<tr>
<td class="header-logo">
<img src="{{ asset('images/ri_1.png') }}" alt="logo" id="logo" class="logo">
</td>
<td class="header-cief-address">
<span class="company-name">
<strong>
CIEF WORLDWIDE SDN BHD
</strong>
</span>
<span class="company-reg">(1134596-M)</span><br>
No. 72-3, Jalan Jalil 1,<br>
The Earth Bukit Jalil,<br>
57000 Kuala Lumpur<br>
Tel: 03-8082 1252
</td>
<td class="header-details">
<div class="title" style="font-size: 20px; text-transform: uppercase;">
<strong>
Invoice
</strong>
</div>
<div class="number">Invoice No: {{ $invoice_transaction->bill_no }}</div>
@php
$companyModule = $invoice_transaction->owner->owner->companyModule;
@endphp
<div class="date">Date: {{ $invoice_transaction->created_at }}</div>
<div class="ref">Order No: {{ $invoice_transaction->owner->owner->reference }}</div>
<div class="ref">Container Ref: {{ $invoice_transaction->owner->containers()->first()->reference }}</div>
{{--<div class="d-none">{{ $companyModule->inviters()->withPivot('invitee_reference')->first()->pivot->invitee_reference }}</div>--}}
<div>&nbsp;</div>
</div>
</td>
</tr>
<tr>
<td colspan="3" class="bill-to">
<span class="sub-title">
Bill To
</span>
</td>
</tr>
<tr>
<td colspan="3" class="address">
<div class="label">
{{ $companyModule->name }}
</div>
<div class="address">
@php
$addresses = $companyModule->addresses()->where('status', '=', \App\Classes\ValueObjects\Constants\ApprovalStatus::APPROVED)->where('type', '=', \App\Classes\ValueObjects\Constants\AddressType::BILLING)->first();
@endphp
{{ $addresses->street_one }}
{{ $addresses->street_two }} ,
{{ $addresses->district()->first()->name }},
{{ $addresses->postcode }}
{{ $addresses->state()->first()->name }},
{{ $addresses->country()->first()->name }}
</div>
<div>
@php
$contact = $companyModule->contacts()->first();
@endphp
Phone: {{ $contact ? $contact->phone : '' }}
</div>
</td>
</tr>
</table>
<br>
<br>
<table class="line-table" style="overflow: wrap" autosize="1">
<thead>
<tr>
<th width="5%">No</th>
<th class="description">Description</th>
<th width="15%">Quantity</th>
<th width="20%">Unit Price (RM)</th>
<th width="20%">Total Amount<br>(RM)</th>
</tr>
</thead>
<tbody>
@foreach ($invoice_transaction->transactionDetails as $key => $transaction_detail)
<tr>
<td width="5%" class="center top">{{ $key + 1 }}</td>
<td class="description">{!! $transaction_detail->name !!}</td>
<td width="15%" class="center top" style="text-align: center">{{ round($transaction_detail->quantity, 3) }}</td>
<td width="20%" class="center top" style="text-align: center">
{{ round($transaction_detail->price, 2) }}
</td>
<td width="20%" class="right top">
{{ round($transaction_detail->amount, 2) }}
</td>
</tr>
@endforeach
</tbody>
<tfoot>
<tr class="subtotal">
<td colspan="3"></td>
<td class="right middle">Subtotal</td>
<td class="right middle">
{{ round($invoice_transaction->amount, 2) }}
</td>
</tr>
<tr class="billingcharges">
<td colspan="3"></td>
<td class="right">Service Charges</td>
<td class="right">
{{ round($invoice_transaction->service_charge, 2) }}
</td>
</tr>
@if($invoice_transaction->tax > 0)
<tr class="billingcharges">
<td colspan="3"></td>
<td class="right">Tax</td>
<td class="right">{{ number_format($invoice_transaction->tax, 2) }}</td>
</tr>
@endif
<tr>
<td colspan="3"></td>
<td class="right middle">Total</td>
<td class="total right middle">
{{ round($invoice_transaction->amount, 2) }}
</td>
</tr>
</tfoot>
</table>
<htmlpagefooter name="page-footer">
<table width="100%">
<tr>
<td style="text-align: right; ">This is generated by computer. No signature required.</td>
<td style="text-align: right; ">Page {PAGENO} of {nbpg}</td>
</tr>
</table>
</htmlpagefooter>
@endforeach
@endsection
File diff suppressed because one or more lines are too long
+2
View File
@@ -33,4 +33,6 @@ Route::group(['prefix' => 'company', 'as' => 'company.', 'namespace' => 'Compani
});
Route::get('/module/list', 'ListCompanyModulesController@list')->name('module.list');
Route::get('/{company_module_id}/invoice/list', 'ListCompanyModuleInvoicesController@list')->name('invoice.list');
});
+7 -2
View File
@@ -13,13 +13,18 @@ Route::group(['prefix' => 'transactions', 'namespace' => 'Transactions', 'as' =>
Route::post('/upload-verification-document/{transaction_id}', 'UploadPaymentVerificationDocumentController@upload')->name('verification.create');
Route::put('/approve/{transaction_id}/{status}', 'ApprovePaymentTransactionController@approve')->where('status', 'approve|reject')->name('approval');
});
Route::group(['prefix' => 'invoice', 'as' => 'invoice.'], function () {
route::post('/shipping-invoice/create', 'CreateShippingInvoiceTransactionController@create')->name('create');
route::put('/shipping-invoice/{id}/update', 'UpdateShippingInvoiceTransactionController@update')->name('update');
route::put('/shipping-invoice/{id}/approve', 'ApproveShippingInvoiceTransactionController@approve')->name('approve');
});
Route::group(['prefix' => 'invoices', 'as' => 'invoices.'], function () {
route::put('/combine', 'CreateCombinedInvoicesController@combine')->name('combine');
});
route::post('/shipping-invoice/calculator', 'ShippingEstimationCalculatorController@calculate')->name('shipping.estimation.calculator');
// Route::group(['prefix' => '{id}/payment', 'as' => 'payment.'], function () {
@@ -34,4 +39,4 @@ Route::group(['prefix' => 'transactions', 'namespace' => 'Transactions', 'as' =>
// Route::post('booking/{id}/details/update', 'CreatePurchaseOrderTransactionController@create')->name('po.create');
});
});
+8 -2
View File
@@ -160,6 +160,12 @@ Route::get('/customer/{marking}/details', function ($marking) {
return view('pages.customers.profile_details', ['id' => $id]);
})->name('customer.profile.details');
Route::get('/customer/{marking}/payment-and-billing', function ($marking) {
$connection = CompanyConnection::where('invitee_reference', $marking)->first();
$company_module_id = $connection->invitee->id;
return view('pages.customers.paymentsBilling', ['company_module_id' => $company_module_id]);
})->name('customer.payment-and-billing');
Route::get('/orders/refresh', function(\Illuminate\Http\Request $request){
$packingLists = \App\Models\PackingList::where('type', \App\Classes\ValueObjects\Constants\PackingListType::WAREHOUSE_RECEIVE_LIST)->has('containers')->get();
dd($packingLists);
@@ -198,9 +204,9 @@ Route::get('/order/{id}/download', 'Orders\DownloadOrderQrPdfController@download
Route::get('/report/customclearance/{orderid}', 'Reports\CustomcClearanceReportController@download')->name('report.customclearance');
Route::group(['prefix' => 'template', 'as' => 'template.'], function () {
Route::get('/payments-and-billing', function () {
Route::get('/payment-and-billing', function () {
return view('pages.templates.paymentsBilling');
})->name('payments-and-billing');
})->name('payment-and-billing');
Route::get('/shipping-queue', function () {
return view('pages.templates.shippingQueue');