Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,18 @@

namespace App\Http\Controllers\Api\Purchase\PurchaseOrder;

use App\Exceptions\PointException;
use App\Http\Controllers\Controller;
use App\Http\Resources\ApiResource;
use App\Mail\PurchaseOrderBulkRequestApprovalNotificationMail;
use App\Model\Master\User;
use App\Model\Project\Project;
use App\Model\Purchase\PurchaseOrder\PurchaseOrder;
use App\Model\Token;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;

class PurchaseOrderApprovalController extends Controller
{
Expand All @@ -22,6 +30,8 @@ public function approve(Request $request, $id)
$purchaseOrder->form->approval_status = 1;
$purchaseOrder->form->save();

$purchaseOrder->form->fireEventApproved();

return new ApiResource($purchaseOrder);
}

Expand All @@ -39,6 +49,131 @@ public function reject(Request $request, $id)
$purchaseOrder->form->approval_status = -1;
$purchaseOrder->form->save();

$purchaseOrder->form->fireEventRejected();

return new ApiResource($purchaseOrder);
}

/**
* @param Request $request
* @return JsonResponse
*/
public function sendBulkRequestApproval(Request $request)
{
$purchaseOrderGroup = PurchaseOrder::whereIn('id', $request->get('bulk_id'))
->with('form.requestApprovalTo','form.createdBy', 'supplier', 'items')
->get()
->groupBy('form.requestApprovalTo.email');

foreach($purchaseOrderGroup as $email => $purchaseOrders){
// create token based on request_approval_to
$approver = User::findOrFail($purchaseOrders[0]->form->request_approval_to);
$token = Token::where('user_id', $approver->id)->first();

if (!$token) {
$token = new Token([
'user_id' => $approver->id,
'token' => md5($approver->email.''.now()),
]);
$token->save();
}

$project = Project::where('code', $request->header('Tenant'))->first();

Mail::to($email)->send(new PurchaseOrderBulkRequestApprovalNotificationMail($purchaseOrders, $request->header('Tenant'), $request->get('tenant_url'), $request->get('bulk_id'), $token->token, $project->name));

// record history
foreach($purchaseOrders as $purchaseOrder){
$purchaseOrder->form->fireEventRequestApproval();
}
}

return response()->json([], 204);
}

/**
* @param Request $request
* @param $id
* @return Json
* @throws PointException
*/
public function approvalWithToken(Request $request)
{
return DB::connection('tenant')->transaction(function () use ($request) {
// verify token
$token = Token::where('token', $request->get('token'))->first();
if(!$token){
throw new PointException('Not Authorized');
}

$purchaseOrder = PurchaseOrder::with('form')->findOrFail($request->get('id'));
if($purchaseOrder->form->approval_status == 0){
if($request->get('status') == -1 || $request->get('status') == 1) {
$purchaseOrder->form->approval_by = $token->user_id;
$purchaseOrder->form->approval_at = now();
$purchaseOrder->form->approval_status = $request->get('status');
if($request->get('status') == -1) {
$purchaseOrder->form->approval_reason = 'rejected by email';
} else if($request->get('status') == 1) {
$purchaseOrder->form->approval_reason = 'approved by email';
}
$purchaseOrder->form->save();

// record history
if($request->get('status') == -1) {
$purchaseOrder->form->fireEventRejectedByEmail();
} else if($request->get('status') == 1) {
$purchaseOrder->form->fireEventApprovedByEmail();
}
}
}

return new ApiResource($purchaseOrder);
});
}

/**
* @param Request $request
* @param $id
* @return ApiResource
* @throws UnauthorizedException
* @throws ApprovalNotFoundException
*/
public function bulkApprovalWithToken(Request $request)
{
return DB::connection('tenant')->transaction(function () use ($request) {
// verify token
$token = Token::where('token', $request->get('token'))->first();
if(!$token){
throw new PointException('Not Authorized');
}

$bulkId = $request->get('bulk_id');
$purchaseOrders = PurchaseOrder::with('form')->whereIn('id', $bulkId)->get();
foreach($purchaseOrders as $purchaseOrder) {
if($purchaseOrder->form->approval_status == 0){
if($request->get('status') == -1 || $request->get('status') == 1) {
$purchaseOrder->form->approval_by = $token->user_id;
$purchaseOrder->form->approval_at = now();
$purchaseOrder->form->approval_status = $request->get('status');
if($request->get('status') == -1) {
$purchaseOrder->form->approval_reason = 'rejected by email';
} else if($request->get('status') == 1) {
$purchaseOrder->form->approval_reason = 'approved by email';
}
$purchaseOrder->form->save();

// record history
if($request->get('status') == -1) {
$purchaseOrder->form->fireEventRejectedByEmail();
} else if($request->get('status') == 1) {
$purchaseOrder->form->fireEventApprovedByEmail();
}
}
}
}

return new ApiResource($purchaseOrders);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ public function approve(Request $request, $id)

$purchaseOrder->updateReference();

$purchaseOrder->form->fireEventCancelApproved();

DB::connection('tenant')->commit();

return new ApiResource($purchaseOrder);
Expand All @@ -46,6 +48,8 @@ public function reject(Request $request, $id)
$purchaseOrder->form->cancellation_status = -1;
$purchaseOrder->form->save();

$purchaseOrder->form->fireEventCancelRejected();

return new ApiResource($purchaseOrder);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use App\Http\Resources\ApiResource;
use App\Model\Master\Supplier;
use App\Model\Purchase\PurchaseOrder\PurchaseOrder;
use App\Model\UserActivity;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Throwable;
Expand All @@ -32,6 +33,21 @@ public function index(Request $request)
return new ApiCollection($purchaseOrders);
}

/**
* Display a listing of the resource.
*
* @param \Illuminate\Http\Request $request
* @return ApiCollection
*/
public function history(Request $request)
{
$userActivity = UserActivity::from(UserActivity::getTableName().' as '.UserActivity::$alias)->eloquentFilter($request);

$userActivity = pagination($userActivity, $request->get('limit'));

return new ApiCollection($userActivity);
}

/**
* Store a newly created resource in storage.
* Request :
Expand Down
46 changes: 46 additions & 0 deletions app/Mail/PurchaseOrderBulkRequestApprovalNotificationMail.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;

class PurchaseOrderBulkRequestApprovalNotificationMail extends Mailable
{
use Queueable, SerializesModels;

public $purchaseOrders;
public $tenant;
public $tenantUrl;
public $bulkId;
public $token;
public $projectName;

/**
* Create a new message instance.
*
* @param $employeeContractExpired
* @param $employeeContractExpiredSoon
*/
public function __construct($purchaseOrders, $tenant, $tenantUrl, $bulkId, $token, $projectName)
{
$this->purchaseOrders = $purchaseOrders;
$this->tenant = $tenant;
$this->tenantUrl = $tenantUrl;
$this->bulkId = $bulkId;
$this->token = $token;
$this->projectName = $projectName;
}

/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->subject('Approval Email Purchase Order')
->view('emails.purchase.purchase-order.bulk-request-approval-notification');
}
}
2 changes: 1 addition & 1 deletion app/Model/Purchase/PurchaseOrder/PurchaseOrder.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public function updateStatus() {
}
}

public static function create($data)
public static function create($data): PurchaseOrder
{
$purchaseOrder = new self;
$purchaseOrder->fill($data);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
@extends('emails.template')

@section('content')
<div style="align-content: center;position: center;text-align: center; font-family: Helvetica, Roboto, sans-serif;">
<div class="title" style="text-align: center">Purchase Order</div>
<hr>
<div style="align-content: left;position: left;text-align: left">
<h4>Hello Mrs/Mr/Ms {{ $purchaseOrders[0]->form->requestApprovalTo->full_name }}</h4>
<p>You have an approval for Purchase Order. We would like to details as follows: </p>
<table border="0">
<tbody>
<tr>
<td>Form number</td>
<td>: {{$purchaseOrders[0]->form->number}} - {{$purchaseOrders[count($purchaseOrders)-1]->form->number}}</td>
</tr>
<tr>
<td>Form date</td>
<td>: {{date('d F Y', strtotime($purchaseOrders[0]->form->date))}} - {{date('d F Y', strtotime($purchaseOrders[count($purchaseOrders)-1]->form->date))}}</td>
</tr>
<tr>
<td>Created at</td>
<td>: {{date('d F Y H:i', strtotime($purchaseOrders[0]->created_at))}} - {{date('d F Y H:i', strtotime($purchaseOrders[count($purchaseOrders)-1]->created_at))}}</td>
</tr>
</tbody>
</table>
</div>
<table border="1" width="100%">
<thead>
<tr>
<th style="padding: 5px">No</th>
<th style="padding: 5px; min-width:120px;">Date Form</th>
<th style="padding: 5px">Form Number</th>
<th style="padding: 5px">Supplier</th>
<th style="padding: 5px">Items</th>
<th style="padding: 5px">Note</th>
<th style="padding: 5px">Tax</th>
<th style="padding: 5px">Discount</th>
<th style="padding: 5px">Amount</th>
<th style="padding: 5px">Action</th>
</tr>
</thead>
<tbody>
@foreach($purchaseOrders as $index => $purchaseOrder)
<tr>
<td style="padding: 5px">{{ $index + 1 }}</td>
<td style="padding: 5px; text-align: center">{{ date('d F Y', strtotime($purchaseOrder->form->date.' Asia/Jakarta')) }}</td>
<td style="padding: 5px; text-align: center">{{ $purchaseOrder->form->number }}</td>
<td style="padding: 5px; text-align: center">{{ $purchaseOrder->supplier->name }}</td>
<td style="padding: 5px; text-align: center">{{ $purchaseOrder->items->count() }}</td>
<td style="padding: 5px; text-align: center">{{ $purchaseOrder->form->notes }}</td>
<td style="padding: 5px; text-align: center">{{ $purchaseOrder->tax }}</td>
<td style="padding: 5px; text-align: center">{{ $purchaseOrder->discount ?: 0 }} ({{ ucwords($purchaseOrder->type_of_tax) }})</td>
<td style="padding: 5px; text-align: center">{{ $purchaseOrder->amount }}</td>
<td style="padding: 5px; text-align: center;">
<div style="display: flex;">
<a href="{{$tenantUrl}}/purchase/order/{{$purchaseOrder->id}}" style="padding: 5px 15px 5px 15px; margin: 2px; min-width: 30px; border-radius: 5px; background-color:#666699; color:white; text-decoration: none;">Check</a>
<a href="{{$tenantUrl}}/approval?resource-type=PurchaseOrder&tenant={{$tenant}}&action=approve&id={{$purchaseOrder->id}}&project-name={{$projectName}}&token={{$token}}" style="padding: 5px 15px 5px 15px; margin: 2px; min-width: 30px; border-radius: 5px; background-color:#1aa3ff; color:white; text-decoration: none;">Approve</a>
<a href="{{$tenantUrl}}/approval?resource-type=PurchaseOrder&tenant={{$tenant}}&action=reject&id={{$purchaseOrder->id}}&project-name={{$projectName}}&token={{$token}}" style="padding: 5px 15px 5px 15px; margin: 2px; min-width: 30px; border-radius: 5px; background-color:#ff3333; color:white; text-decoration: none;">Reject</a>
</div>
</td>
</tr>
@endforeach
</tbody>
</table>
<div style="display: flex; margin-top:15px">
<a href="{{$tenantUrl}}/approval-all?resource-type=PurchaseOrder&tenant={{$tenant}}&action=approve&ids={{json_encode($bulkId)}}&project-name={{$projectName}}&token={{$token}}" style="padding: 5px 15px 5px 15px; margin: 2px; min-width: 30px; border-radius: 5px; background-color:#1aa3ff; color:white; text-decoration: none;">Approve All</a>
<a href="{{$tenantUrl}}/approval-all?resource-type=PurchaseOrder&tenant={{$tenant}}&action=reject&ids={{json_encode($bulkId)}}&project-name={{$projectName}}&token={{$token}}" style="padding: 5px 15px 5px 15px; margin: 2px; min-width: 30px; border-radius: 5px; background-color:#ff3333; color:white; text-decoration: none;">Reject All</a>
</div>
</div>
@stop
10 changes: 6 additions & 4 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,19 @@
});

Route::prefix('sales/return')->namespace('Sales\\SalesReturn')
->middleware('tenant.module-access:sales return')
->middleware('tenant.module-access:sales return')
->group(function () {
Route::post('/approve', 'SalesReturnApprovalByEmailController@approve');
Route::post('/reject', 'SalesReturnApprovalByEmailController@reject');
});

Route::prefix('sales/delivery-orders')->namespace('Sales\\DeliveryOrder')
->middleware('tenant.module-access:sales delivery order')
->middleware('tenant.module-access:sales delivery order')
->group(function () {
Route::post('/approve', 'DeliveryOrderApprovalByEmailController@approve');
Route::post('/reject', 'DeliveryOrderApprovalByEmailController@reject');
});

Route::prefix('accounting/memo-journals')->namespace('Accounting')->group(function () {
Route::post('/approve', 'MemoJournalApprovalByEmailController@approve');
Route::post('/reject', 'MemoJournalApprovalByEmailController@reject');
Expand Down Expand Up @@ -110,10 +110,12 @@
Route::get('oauth/login/google/drive', 'OAuthController@requestGoogleDrive');
Route::post('oauth/login/google/drive', 'OAuthController@storeGoogleAccessToken');
Route::delete('oauth/login/google/drive', 'OAuthController@unlinkGoogleDrive');

//Approve/reject with token
Route::prefix('approval-with-token')->group(function () {
Route::post('finance/cash-advances', 'Finance\\CashAdvance\\CashAdvanceApprovalController@approvalWithToken');
Route::post('finance/cash-advances/bulk', 'Finance\\CashAdvance\\CashAdvanceApprovalController@bulkApprovalWithToken');
Route::post('purchase/orders', 'Purchase\\PurchaseOrder\\PurchaseOrderApprovalController@approvalWithToken');
Route::post('purchase/orders/bulk', 'Purchase\\PurchaseOrder\\PurchaseOrderApprovalController@bulkApprovalWithToken');
});
});
2 changes: 2 additions & 0 deletions routes/api/purchase.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
Route::apiResource('requests', 'PurchaseRequest\\PurchaseRequestController');
Route::post('orders/{id}/approve', 'PurchaseOrder\\PurchaseOrderApprovalController@approve');
Route::post('orders/{id}/reject', 'PurchaseOrder\\PurchaseOrderApprovalController@reject');
Route::post('orders/send-bulk-request-approval', 'PurchaseOrder\\PurchaseOrderApprovalController@sendBulkRequestApproval');
Route::post('orders/{id}/cancellation-approve', 'PurchaseOrder\\PurchaseOrderCancellationApprovalController@approve');
Route::post('orders/{id}/cancellation-reject', 'PurchaseOrder\\PurchaseOrderCancellationApprovalController@reject');
Route::get('orders/history', 'PurchaseOrder\\PurchaseOrderController@history');
Route::apiResource('orders', 'PurchaseOrder\\PurchaseOrderController');
Route::post('down-payments/{id}/approve', 'PurchaseDownPayment\\PurchaseDownPaymentApprovalController@approve');
Route::post('down-payments/{id}/reject', 'PurchaseDownPayment\\PurchaseDownPaymentApprovalController@reject');
Expand Down
Loading