1441 lines
65 KiB
PHP
1441 lines
65 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\AccountTransaction;
|
|
use App\Business;
|
|
use App\BusinessLocation;
|
|
use App\Contact;
|
|
use App\CustomerGroup;
|
|
use App\Product;
|
|
use App\PurchaseLine;
|
|
use App\TaxRate;
|
|
use App\Transaction;
|
|
use App\User;
|
|
use App\Utils\BusinessUtil;
|
|
use App\Utils\ModuleUtil;
|
|
use App\Utils\ProductUtil;
|
|
use App\Utils\TransactionUtil;
|
|
use App\Variation;
|
|
use Excel;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Spatie\Activitylog\Models\Activity;
|
|
use Yajra\DataTables\Facades\DataTables;
|
|
use App\Events\PurchaseCreatedOrModified;
|
|
|
|
class PurchaseController extends Controller
|
|
{
|
|
/**
|
|
* All Utils instance.
|
|
*/
|
|
protected $productUtil;
|
|
|
|
protected $transactionUtil;
|
|
|
|
protected $moduleUtil;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param ProductUtils $product
|
|
* @return void
|
|
*/
|
|
public function __construct(ProductUtil $productUtil, TransactionUtil $transactionUtil, BusinessUtil $businessUtil, ModuleUtil $moduleUtil)
|
|
{
|
|
$this->productUtil = $productUtil;
|
|
$this->transactionUtil = $transactionUtil;
|
|
$this->businessUtil = $businessUtil;
|
|
$this->moduleUtil = $moduleUtil;
|
|
|
|
$this->dummyPaymentLine = ['method' => 'cash', 'amount' => 0, 'note' => '', 'card_transaction_number' => '', 'card_number' => '', 'card_type' => '', 'card_holder_name' => '', 'card_month' => '', 'card_year' => '', 'card_security' => '', 'cheque_number' => '', 'bank_account_number' => '',
|
|
'is_return' => 0, 'transaction_no' => '', ];
|
|
}
|
|
|
|
/**
|
|
* Display a listing of the resource.
|
|
*
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function index()
|
|
{
|
|
if (! auth()->user()->can('purchase.view') && ! auth()->user()->can('purchase.create') && ! auth()->user()->can('view_own_purchase')) {
|
|
abort(403, 'Unauthorized action.');
|
|
}
|
|
$business_id = request()->session()->get('user.business_id');
|
|
if (request()->ajax()) {
|
|
$purchases = $this->transactionUtil->getListPurchases($business_id);
|
|
|
|
$permitted_locations = auth()->user()->permitted_locations();
|
|
if ($permitted_locations != 'all') {
|
|
$purchases->whereIn('transactions.location_id', $permitted_locations);
|
|
}
|
|
|
|
if (! empty(request()->supplier_id)) {
|
|
$purchases->where('contacts.id', request()->supplier_id);
|
|
}
|
|
if (! empty(request()->location_id)) {
|
|
$purchases->where('transactions.location_id', request()->location_id);
|
|
}
|
|
if (! empty(request()->input('payment_status')) && request()->input('payment_status') != 'overdue') {
|
|
$purchases->where('transactions.payment_status', request()->input('payment_status'));
|
|
} elseif (request()->input('payment_status') == 'overdue') {
|
|
$purchases->whereIn('transactions.payment_status', ['due', 'partial'])
|
|
->whereNotNull('transactions.pay_term_number')
|
|
->whereNotNull('transactions.pay_term_type')
|
|
->whereRaw("IF(transactions.pay_term_type='days', DATE_ADD(transactions.transaction_date, INTERVAL transactions.pay_term_number DAY) < CURDATE(), DATE_ADD(transactions.transaction_date, INTERVAL transactions.pay_term_number MONTH) < CURDATE())");
|
|
}
|
|
|
|
if (! empty(request()->status)) {
|
|
$purchases->where('transactions.status', request()->status);
|
|
}
|
|
|
|
if (! empty(request()->start_date) && ! empty(request()->end_date)) {
|
|
$start = request()->start_date;
|
|
$end = request()->end_date;
|
|
$purchases->whereDate('transactions.transaction_date', '>=', $start)
|
|
->whereDate('transactions.transaction_date', '<=', $end);
|
|
}
|
|
|
|
if (! auth()->user()->can('purchase.view') && auth()->user()->can('view_own_purchase')) {
|
|
$purchases->where('transactions.created_by', request()->session()->get('user.id'));
|
|
}
|
|
|
|
return Datatables::of($purchases)
|
|
->addColumn('action', function ($row) {
|
|
$html = '<div class="btn-group">
|
|
<button type="button" class="btn-modal tw-dw-btn tw-dw-btn-xs tw-dw-btn-outline tw-dw-btn-info tw-w-max dropdown-toggle"
|
|
data-toggle="dropdown" aria-expanded="false">'.
|
|
__('messages.actions').
|
|
'<span class="caret"></span><span class="sr-only">Toggle Dropdown
|
|
</span>
|
|
</button>
|
|
<ul class="dropdown-menu dropdown-menu-left" role="menu">';
|
|
if (auth()->user()->can('purchase.view')) {
|
|
$html .= '<li><a href="#" data-href="'.action([\App\Http\Controllers\PurchaseController::class, 'show'], [$row->id]).'" class="btn-modal" data-container=".view_modal"><i class="fas fa-eye" aria-hidden="true"></i>'.__('messages.view').'</a></li>';
|
|
}
|
|
if (auth()->user()->can('purchase.view')) {
|
|
$html .= '<li><a href="#" class="print-invoice" data-href="'.action([\App\Http\Controllers\PurchaseController::class, 'printInvoice'], [$row->id]).'"><i class="fas fa-print" aria-hidden="true"></i>'.__('messages.print').'</a></li>';
|
|
}
|
|
if (auth()->user()->can('purchase.update')) {
|
|
$html .= '<li><a href="'.action([\App\Http\Controllers\PurchaseController::class, 'edit'], [$row->id]).'"><i class="fas fa-edit"></i>'.__('messages.edit').'</a></li>';
|
|
}
|
|
if (auth()->user()->can('purchase.delete')) {
|
|
$html .= '<li><a href="'.action([\App\Http\Controllers\PurchaseController::class, 'destroy'], [$row->id]).'" class="delete-purchase"><i class="fas fa-trash"></i>'.__('messages.delete').'</a></li>';
|
|
}
|
|
|
|
$html .= '<li><a href="'.action([\App\Http\Controllers\LabelsController::class, 'show']).'?purchase_id='.$row->id.'" data-toggle="tooltip" title="'.__('lang_v1.label_help').'"><i class="fas fa-barcode"></i>'.__('barcode.labels').'</a></li>';
|
|
|
|
if (auth()->user()->can('purchase.view') && ! empty($row->document)) {
|
|
$document_name = ! empty(explode('_', $row->document, 2)[1]) ? explode('_', $row->document, 2)[1] : $row->document;
|
|
$html .= '<li><a href="'.url('uploads/documents/'.$row->document).'" download="'.$document_name.'"><i class="fas fa-download" aria-hidden="true"></i>'.__('purchase.download_document').'</a></li>';
|
|
if (isFileImage($document_name)) {
|
|
$html .= '<li><a href="#" data-href="'.url('uploads/documents/'.$row->document).'" class="view_uploaded_document"><i class="fas fa-image" aria-hidden="true"></i>'.__('lang_v1.view_document').'</a></li>';
|
|
}
|
|
}
|
|
|
|
if (auth()->user()->can('purchase.payments') ||
|
|
auth()->user()->can('edit_purchase_payment') ||
|
|
auth()->user()->can('delete_purchase_payment')) {
|
|
$html .= '<li class="divider"></li>';
|
|
if ($row->payment_status != 'paid') {
|
|
$html .= '<li><a href="'.action([\App\Http\Controllers\TransactionPaymentController::class, 'addPayment'], [$row->id]).'" class="add_payment_modal"><i class="fas fa-money-bill-alt" aria-hidden="true"></i>'.__('purchase.add_payment').'</a></li>';
|
|
}
|
|
|
|
$html .= '<li><a href="'.action([\App\Http\Controllers\TransactionPaymentController::class, 'show'], [$row->id]).
|
|
'" class="view_payment_modal"><i class="fas fa-money-bill-alt" aria-hidden="true" ></i>'.__('purchase.view_payments').'</a></li>';
|
|
}
|
|
|
|
if (auth()->user()->can('purchase.update')) {
|
|
$html .= '<li><a href="'.action([\App\Http\Controllers\PurchaseReturnController::class, 'add'], [$row->id]).
|
|
'"><i class="fas fa-undo" aria-hidden="true" ></i>'.__('lang_v1.purchase_return').'</a></li>';
|
|
}
|
|
|
|
if (auth()->user()->can('purchase.update') || auth()->user()->can('purchase.update_status')) {
|
|
$html .= '<li><a href="#" data-purchase_id="'.$row->id.
|
|
'" data-status="'.$row->status.'" class="update_status"><i class="fas fa-edit" aria-hidden="true" ></i>'.__('lang_v1.update_status').'</a></li>';
|
|
}
|
|
|
|
if ($row->status == 'ordered') {
|
|
$html .= '<li><a href="#" data-href="'.action([\App\Http\Controllers\NotificationController::class, 'getTemplate'], ['transaction_id' => $row->id, 'template_for' => 'new_order']).'" class="btn-modal" data-container=".view_modal"><i class="fas fa-envelope" aria-hidden="true"></i> '.__('lang_v1.new_order_notification').'</a></li>';
|
|
} elseif ($row->status == 'received') {
|
|
$html .= '<li><a href="#" data-href="'.action([\App\Http\Controllers\NotificationController::class, 'getTemplate'], ['transaction_id' => $row->id, 'template_for' => 'items_received']).'" class="btn-modal" data-container=".view_modal"><i class="fas fa-envelope" aria-hidden="true"></i> '.__('lang_v1.item_received_notification').'</a></li>';
|
|
} elseif ($row->status == 'pending') {
|
|
$html .= '<li><a href="#" data-href="'.action([\App\Http\Controllers\NotificationController::class, 'getTemplate'], ['transaction_id' => $row->id, 'template_for' => 'items_pending']).'" class="btn-modal" data-container=".view_modal"><i class="fas fa-envelope" aria-hidden="true"></i> '.__('lang_v1.item_pending_notification').'</a></li>';
|
|
}
|
|
|
|
$html .= '</ul></div>';
|
|
|
|
return $html;
|
|
})
|
|
->removeColumn('id')
|
|
->editColumn('ref_no', function ($row) {
|
|
return ! empty($row->return_exists) ? e($row->ref_no).' <small class="label bg-red label-round no-print" title="'.__('lang_v1.some_qty_returned').'"><i class="fas fa-undo"></i></small>' : e($row->ref_no);
|
|
})
|
|
->editColumn(
|
|
'final_total',
|
|
'<span class="final_total" data-orig-value="{{$final_total}}">@format_currency($final_total)</span>'
|
|
)
|
|
->editColumn('transaction_date', '@format_datetime($transaction_date)')
|
|
->editColumn('name', '@if(!empty($supplier_business_name)) {{$supplier_business_name}}, <br> @endif {{$name}}')
|
|
->editColumn(
|
|
'status',
|
|
'<a href="#" @if(auth()->user()->can("purchase.update") || auth()->user()->can("purchase.update_status")) class="update_status no-print" data-purchase_id="{{$id}}" data-status="{{$status}}" @endif><span class="label @transaction_status($status) status-label" data-status-name="{{__(\'lang_v1.\' . $status)}}" data-orig-value="{{$status}}">{{__(\'lang_v1.\' . $status)}}
|
|
</span></a>'
|
|
)
|
|
->editColumn(
|
|
'payment_status',
|
|
function ($row) {
|
|
$payment_status = Transaction::getPaymentStatus($row);
|
|
|
|
return (string) view('sell.partials.payment_status', ['payment_status' => $payment_status, 'id' => $row->id, 'for_purchase' => true]);
|
|
}
|
|
)
|
|
->addColumn('payment_due', function ($row) {
|
|
$due = $row->final_total - $row->amount_paid;
|
|
$due_html = '<strong>'.__('lang_v1.purchase').':</strong> <span class="payment_due" data-orig-value="'.$due.'">'.$this->transactionUtil->num_f($due, true).'</span>';
|
|
|
|
if (! empty($row->return_exists)) {
|
|
$return_due = $row->amount_return - $row->return_paid;
|
|
$due_html .= '<br><strong>'.__('lang_v1.purchase_return').':</strong> <a href="'.action([\App\Http\Controllers\TransactionPaymentController::class, 'show'], [$row->return_transaction_id]).'" class="view_purchase_return_payment_modal"><span class="purchase_return" data-orig-value="'.$return_due.'">'.$this->transactionUtil->num_f($return_due, true).'</span></a>';
|
|
}
|
|
|
|
return $due_html;
|
|
})
|
|
->setRowAttr([
|
|
'data-href' => function ($row) {
|
|
if (auth()->user()->can('purchase.view')) {
|
|
return action([\App\Http\Controllers\PurchaseController::class, 'show'], [$row->id]);
|
|
} else {
|
|
return '';
|
|
}
|
|
}, ])
|
|
->rawColumns(['final_total', 'action', 'payment_due', 'payment_status', 'status', 'ref_no', 'name'])
|
|
->make(true);
|
|
}
|
|
|
|
$business_locations = BusinessLocation::forDropdown($business_id);
|
|
$suppliers = Contact::suppliersDropdown($business_id, false);
|
|
$orderStatuses = $this->productUtil->orderStatuses();
|
|
|
|
return view('purchase.index')
|
|
->with(compact('business_locations', 'suppliers', 'orderStatuses'));
|
|
}
|
|
|
|
/**
|
|
* Show the form for creating a new resource.
|
|
*
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function create()
|
|
{
|
|
if (! auth()->user()->can('purchase.create')) {
|
|
abort(403, 'Unauthorized action.');
|
|
}
|
|
|
|
$business_id = request()->session()->get('user.business_id');
|
|
|
|
//Check if subscribed or not
|
|
if (! $this->moduleUtil->isSubscribed($business_id)) {
|
|
return $this->moduleUtil->expiredResponse();
|
|
}
|
|
|
|
$taxes = TaxRate::where('business_id', $business_id)
|
|
->ExcludeForTaxGroup()
|
|
->get();
|
|
$orderStatuses = $this->productUtil->orderStatuses();
|
|
$business_locations = BusinessLocation::forDropdown($business_id, false, true);
|
|
$bl_attributes = $business_locations['attributes'];
|
|
$business_locations = $business_locations['locations'];
|
|
|
|
$currency_details = $this->transactionUtil->purchaseCurrencyDetails($business_id);
|
|
|
|
$default_purchase_status = null;
|
|
if (request()->session()->get('business.enable_purchase_status') != 1) {
|
|
$default_purchase_status = 'received';
|
|
}
|
|
|
|
$types = [];
|
|
if (auth()->user()->can('supplier.create')) {
|
|
$types['supplier'] = __('report.supplier');
|
|
}
|
|
if (auth()->user()->can('customer.create')) {
|
|
$types['customer'] = __('report.customer');
|
|
}
|
|
if (auth()->user()->can('supplier.create') && auth()->user()->can('customer.create')) {
|
|
$types['both'] = __('lang_v1.both_supplier_customer');
|
|
}
|
|
$customer_groups = CustomerGroup::forDropdown($business_id);
|
|
|
|
$business_details = $this->businessUtil->getDetails($business_id);
|
|
$shortcuts = json_decode($business_details->keyboard_shortcuts, true);
|
|
|
|
$payment_line = $this->dummyPaymentLine;
|
|
$payment_types = $this->productUtil->payment_types(null, true, $business_id);
|
|
|
|
//Accounts
|
|
$accounts = $this->moduleUtil->accountsDropdown($business_id, true);
|
|
|
|
$common_settings = ! empty(session('business.common_settings')) ? session('business.common_settings') : [];
|
|
|
|
return view('purchase.create')
|
|
->with(compact('taxes', 'orderStatuses', 'business_locations', 'currency_details', 'default_purchase_status', 'customer_groups', 'types', 'shortcuts', 'payment_line', 'payment_types', 'accounts', 'bl_attributes', 'common_settings'));
|
|
}
|
|
|
|
/**
|
|
* Store a newly created resource in storage.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function store(Request $request)
|
|
{
|
|
if (! auth()->user()->can('purchase.create')) {
|
|
abort(403, 'Unauthorized action.');
|
|
}
|
|
|
|
try {
|
|
$business_id = $request->session()->get('user.business_id');
|
|
|
|
//Check if subscribed or not
|
|
if (! $this->moduleUtil->isSubscribed($business_id)) {
|
|
return $this->moduleUtil->expiredResponse(action([\App\Http\Controllers\PurchaseController::class, 'index']));
|
|
}
|
|
|
|
$transaction_data = $request->only(['ref_no', 'status', 'contact_id', 'transaction_date', 'total_before_tax', 'location_id', 'discount_type', 'discount_amount', 'tax_id', 'tax_amount', 'shipping_details', 'shipping_charges', 'final_total', 'additional_notes', 'exchange_rate', 'pay_term_number', 'pay_term_type', 'purchase_order_ids']);
|
|
|
|
$exchange_rate = $transaction_data['exchange_rate'];
|
|
|
|
//Reverse exchange rate and save it.
|
|
//$transaction_data['exchange_rate'] = $transaction_data['exchange_rate'];
|
|
|
|
//TODO: Check for "Undefined index: total_before_tax" issue
|
|
//Adding temporary fix by validating
|
|
$request->validate([
|
|
'status' => 'required',
|
|
'contact_id' => 'required',
|
|
'transaction_date' => 'required',
|
|
'total_before_tax' => 'required',
|
|
'location_id' => 'required',
|
|
'final_total' => 'required',
|
|
'document' => 'file|max:'.(config('constants.document_size_limit') / 1000),
|
|
]);
|
|
|
|
$user_id = $request->session()->get('user.id');
|
|
$enable_product_editing = $request->session()->get('business.enable_editing_product_from_purchase');
|
|
|
|
//Update business exchange rate.
|
|
Business::update_business($business_id, ['p_exchange_rate' => ($transaction_data['exchange_rate'])]);
|
|
|
|
$currency_details = $this->transactionUtil->purchaseCurrencyDetails($business_id);
|
|
|
|
//unformat input values
|
|
$transaction_data['total_before_tax'] = $this->productUtil->num_uf($transaction_data['total_before_tax'], $currency_details) * $exchange_rate;
|
|
|
|
// If discount type is fixed them multiply by exchange rate, else don't
|
|
if ($transaction_data['discount_type'] == 'fixed') {
|
|
$transaction_data['discount_amount'] = $this->productUtil->num_uf($transaction_data['discount_amount'], $currency_details) * $exchange_rate;
|
|
} elseif ($transaction_data['discount_type'] == 'percentage') {
|
|
$transaction_data['discount_amount'] = $this->productUtil->num_uf($transaction_data['discount_amount'], $currency_details);
|
|
} else {
|
|
$transaction_data['discount_amount'] = 0;
|
|
}
|
|
|
|
$transaction_data['tax_amount'] = $this->productUtil->num_uf($transaction_data['tax_amount'], $currency_details) * $exchange_rate;
|
|
$transaction_data['shipping_charges'] = $this->productUtil->num_uf($transaction_data['shipping_charges'], $currency_details) * $exchange_rate;
|
|
$transaction_data['final_total'] = $this->productUtil->num_uf($transaction_data['final_total'], $currency_details) * $exchange_rate;
|
|
|
|
$transaction_data['business_id'] = $business_id;
|
|
$transaction_data['created_by'] = $user_id;
|
|
$transaction_data['type'] = 'purchase';
|
|
$transaction_data['payment_status'] = 'due';
|
|
$transaction_data['transaction_date'] = $this->productUtil->uf_date($transaction_data['transaction_date'], true);
|
|
|
|
//upload document
|
|
$transaction_data['document'] = $this->transactionUtil->uploadFile($request, 'document', 'documents');
|
|
|
|
$transaction_data['custom_field_1'] = $request->input('custom_field_1', null);
|
|
$transaction_data['custom_field_2'] = $request->input('custom_field_2', null);
|
|
$transaction_data['custom_field_3'] = $request->input('custom_field_3', null);
|
|
$transaction_data['custom_field_4'] = $request->input('custom_field_4', null);
|
|
|
|
$transaction_data['shipping_custom_field_1'] = $request->input('shipping_custom_field_1', null);
|
|
$transaction_data['shipping_custom_field_2'] = $request->input('shipping_custom_field_2', null);
|
|
$transaction_data['shipping_custom_field_3'] = $request->input('shipping_custom_field_3', null);
|
|
$transaction_data['shipping_custom_field_4'] = $request->input('shipping_custom_field_4', null);
|
|
$transaction_data['shipping_custom_field_5'] = $request->input('shipping_custom_field_5', null);
|
|
|
|
if ($request->input('additional_expense_value_1') != '') {
|
|
$transaction_data['additional_expense_key_1'] = $request->input('additional_expense_key_1');
|
|
$transaction_data['additional_expense_value_1'] = $this->productUtil->num_uf($request->input('additional_expense_value_1'), $currency_details) * $exchange_rate;
|
|
}
|
|
|
|
if ($request->input('additional_expense_value_2') != '') {
|
|
$transaction_data['additional_expense_key_2'] = $request->input('additional_expense_key_2');
|
|
$transaction_data['additional_expense_value_2'] = $this->productUtil->num_uf($request->input('additional_expense_value_2'), $currency_details) * $exchange_rate;
|
|
}
|
|
|
|
if ($request->input('additional_expense_value_3') != '') {
|
|
$transaction_data['additional_expense_key_3'] = $request->input('additional_expense_key_3');
|
|
$transaction_data['additional_expense_value_3'] = $this->productUtil->num_uf($request->input('additional_expense_value_3'), $currency_details) * $exchange_rate;
|
|
}
|
|
|
|
if ($request->input('additional_expense_value_4') != '') {
|
|
$transaction_data['additional_expense_key_4'] = $request->input('additional_expense_key_4');
|
|
$transaction_data['additional_expense_value_4'] = $this->productUtil->num_uf($request->input('additional_expense_value_4'), $currency_details) * $exchange_rate;
|
|
}
|
|
|
|
DB::beginTransaction();
|
|
|
|
//Update reference count
|
|
$ref_count = $this->productUtil->setAndGetReferenceCount($transaction_data['type']);
|
|
//Generate reference number
|
|
if (empty($transaction_data['ref_no'])) {
|
|
$transaction_data['ref_no'] = $this->productUtil->generateReferenceNumber($transaction_data['type'], $ref_count);
|
|
}
|
|
|
|
$transaction = Transaction::create($transaction_data);
|
|
|
|
$purchase_lines = [];
|
|
$purchases = $request->input('purchases');
|
|
|
|
$this->productUtil->createOrUpdatePurchaseLines($transaction, $purchases, $currency_details, $enable_product_editing);
|
|
|
|
//Add Purchase payments
|
|
$this->transactionUtil->createOrUpdatePaymentLines($transaction, $request->input('payment'));
|
|
|
|
//update payment status
|
|
$payment_status = $this->transactionUtil->updatePaymentStatus($transaction->id, $transaction->final_total);
|
|
|
|
$transaction->payment_status = $payment_status;
|
|
|
|
if (! empty($transaction->purchase_order_ids)) {
|
|
$this->transactionUtil->updatePurchaseOrderStatus($transaction->purchase_order_ids);
|
|
}
|
|
|
|
//Adjust stock over selling if found
|
|
$this->productUtil->adjustStockOverSelling($transaction);
|
|
|
|
$this->transactionUtil->activityLog($transaction, 'added');
|
|
|
|
PurchaseCreatedOrModified::dispatch($transaction);
|
|
|
|
DB::commit();
|
|
|
|
$output = ['success' => 1,
|
|
'msg' => __('purchase.purchase_add_success'),
|
|
];
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
\Log::emergency('File:'.$e->getFile().'Line:'.$e->getLine().'Message:'.$e->getMessage());
|
|
|
|
$output = ['success' => 0,
|
|
'msg' => __('messages.something_went_wrong'),
|
|
];
|
|
}
|
|
|
|
return redirect('purchases')->with('status', $output);
|
|
}
|
|
|
|
/**
|
|
* Display the specified resource.
|
|
*
|
|
* @param int $id
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function show($id)
|
|
{
|
|
// if (!auth()->user()->can('purchase.view')) {
|
|
// abort(403, 'Unauthorized action.');
|
|
// }
|
|
|
|
$business_id = request()->session()->get('user.business_id');
|
|
$taxes = TaxRate::where('business_id', $business_id)
|
|
->pluck('name', 'id');
|
|
$purchase = Transaction::where('business_id', $business_id)
|
|
->where('id', $id)
|
|
->with(
|
|
'contact',
|
|
'purchase_lines',
|
|
'purchase_lines.product',
|
|
'purchase_lines.product.unit',
|
|
'purchase_lines.product.second_unit',
|
|
'purchase_lines.variations',
|
|
'purchase_lines.variations.product_variation',
|
|
'purchase_lines.sub_unit',
|
|
'location',
|
|
'payment_lines',
|
|
'tax'
|
|
)
|
|
->firstOrFail();
|
|
|
|
foreach ($purchase->purchase_lines as $key => $value) {
|
|
if (! empty($value->sub_unit_id)) {
|
|
$formated_purchase_line = $this->productUtil->changePurchaseLineUnit($value, $business_id);
|
|
$purchase->purchase_lines[$key] = $formated_purchase_line;
|
|
}
|
|
}
|
|
|
|
$payment_methods = $this->productUtil->payment_types($purchase->location_id, true);
|
|
|
|
$purchase_taxes = [];
|
|
if (! empty($purchase->tax)) {
|
|
if ($purchase->tax->is_tax_group) {
|
|
$purchase_taxes = $this->transactionUtil->sumGroupTaxDetails($this->transactionUtil->groupTaxDetails($purchase->tax, $purchase->tax_amount));
|
|
} else {
|
|
$purchase_taxes[$purchase->tax->name] = $purchase->tax_amount;
|
|
}
|
|
}
|
|
|
|
//Purchase orders
|
|
$purchase_order_nos = '';
|
|
$purchase_order_dates = '';
|
|
if (! empty($purchase->purchase_order_ids)) {
|
|
$purchase_orders = Transaction::find($purchase->purchase_order_ids);
|
|
|
|
$purchase_order_nos = implode(', ', $purchase_orders->pluck('ref_no')->toArray());
|
|
$order_dates = [];
|
|
foreach ($purchase_orders as $purchase_order) {
|
|
$order_dates[] = $this->transactionUtil->format_date($purchase_order->transaction_date, true);
|
|
}
|
|
$purchase_order_dates = implode(', ', $order_dates);
|
|
}
|
|
|
|
$activities = Activity::forSubject($purchase)
|
|
->with(['causer', 'subject'])
|
|
->latest()
|
|
->get();
|
|
|
|
$statuses = $this->productUtil->orderStatuses();
|
|
|
|
$transaction_show_actions = $this->moduleUtil->getModuleData('transaction_show_actions', ['transaction' => $purchase]);
|
|
|
|
return view('purchase.show')
|
|
->with(compact('taxes', 'purchase', 'payment_methods', 'purchase_taxes', 'activities', 'statuses', 'purchase_order_nos', 'purchase_order_dates', 'transaction_show_actions'));
|
|
}
|
|
|
|
/**
|
|
* Show the form for editing the specified resource.
|
|
*
|
|
* @param int $id
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function edit($id)
|
|
{
|
|
if (! auth()->user()->can('purchase.update')) {
|
|
abort(403, 'Unauthorized action.');
|
|
}
|
|
|
|
$business_id = request()->session()->get('user.business_id');
|
|
|
|
//Check if subscribed or not
|
|
if (! $this->moduleUtil->isSubscribed($business_id)) {
|
|
return $this->moduleUtil->expiredResponse(action([\App\Http\Controllers\PurchaseController::class, 'index']));
|
|
}
|
|
|
|
//Check if the transaction can be edited or not.
|
|
$edit_days = request()->session()->get('business.transaction_edit_days');
|
|
if (! $this->transactionUtil->canBeEdited($id, $edit_days)) {
|
|
return back()
|
|
->with('status', ['success' => 0,
|
|
'msg' => __('messages.transaction_edit_not_allowed', ['days' => $edit_days]), ]);
|
|
}
|
|
|
|
//Check if return exist then not allowed
|
|
if ($this->transactionUtil->isReturnExist($id)) {
|
|
return back()->with('status', ['success' => 0,
|
|
'msg' => __('lang_v1.return_exist'), ]);
|
|
}
|
|
|
|
$business = Business::find($business_id);
|
|
|
|
$currency_details = $this->transactionUtil->purchaseCurrencyDetails($business_id);
|
|
|
|
$taxes = TaxRate::where('business_id', $business_id)
|
|
->ExcludeForTaxGroup()
|
|
->get();
|
|
$purchase = Transaction::where('business_id', $business_id)
|
|
->where('id', $id)
|
|
->with(
|
|
'contact',
|
|
'purchase_lines',
|
|
'purchase_lines.product',
|
|
'purchase_lines.product.unit',
|
|
'purchase_lines.product.second_unit',
|
|
//'purchase_lines.product.unit.sub_units',
|
|
'purchase_lines.variations',
|
|
'purchase_lines.variations.product_variation',
|
|
'location',
|
|
'purchase_lines.sub_unit',
|
|
'purchase_lines.purchase_order_line'
|
|
)
|
|
->first();
|
|
|
|
foreach ($purchase->purchase_lines as $key => $value) {
|
|
if (! empty($value->sub_unit_id)) {
|
|
$formated_purchase_line = $this->productUtil->changePurchaseLineUnit($value, $business_id);
|
|
$purchase->purchase_lines[$key] = $formated_purchase_line;
|
|
}
|
|
}
|
|
|
|
$orderStatuses = $this->productUtil->orderStatuses();
|
|
|
|
$business_locations = BusinessLocation::forDropdown($business_id);
|
|
|
|
$default_purchase_status = null;
|
|
if (request()->session()->get('business.enable_purchase_status') != 1) {
|
|
$default_purchase_status = 'received';
|
|
}
|
|
|
|
$types = [];
|
|
if (auth()->user()->can('supplier.create')) {
|
|
$types['supplier'] = __('report.supplier');
|
|
}
|
|
if (auth()->user()->can('customer.create')) {
|
|
$types['customer'] = __('report.customer');
|
|
}
|
|
if (auth()->user()->can('supplier.create') && auth()->user()->can('customer.create')) {
|
|
$types['both'] = __('lang_v1.both_supplier_customer');
|
|
}
|
|
$customer_groups = CustomerGroup::forDropdown($business_id);
|
|
|
|
$business_details = $this->businessUtil->getDetails($business_id);
|
|
$shortcuts = json_decode($business_details->keyboard_shortcuts, true);
|
|
|
|
$common_settings = ! empty(session('business.common_settings')) ? session('business.common_settings') : [];
|
|
|
|
$purchase_orders = null;
|
|
if (! empty($common_settings['enable_purchase_order'])) {
|
|
$purchase_orders = Transaction::where('business_id', $business_id)
|
|
->where('type', 'purchase_order')
|
|
->where('contact_id', $purchase->contact_id)
|
|
->where(function ($q) use ($purchase) {
|
|
$q->where('status', '!=', 'completed');
|
|
|
|
if (! empty($purchase->purchase_order_ids)) {
|
|
$q->orWhereIn('id', $purchase->purchase_order_ids);
|
|
}
|
|
})
|
|
->pluck('ref_no', 'id');
|
|
}
|
|
|
|
return view('purchase.edit')
|
|
->with(compact(
|
|
'taxes',
|
|
'purchase',
|
|
'orderStatuses',
|
|
'business_locations',
|
|
'business',
|
|
'currency_details',
|
|
'default_purchase_status',
|
|
'customer_groups',
|
|
'types',
|
|
'shortcuts',
|
|
'purchase_orders',
|
|
'common_settings'
|
|
));
|
|
}
|
|
|
|
/**
|
|
* Update the specified resource in storage.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @param int $id
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function update(Request $request, $id)
|
|
{
|
|
if (! auth()->user()->can('purchase.update')) {
|
|
abort(403, 'Unauthorized action.');
|
|
}
|
|
|
|
try {
|
|
$transaction = Transaction::findOrFail($id);
|
|
|
|
//Validate document size
|
|
$request->validate([
|
|
'document' => 'file|max:'.(config('constants.document_size_limit') / 1000),
|
|
]);
|
|
|
|
$transaction = Transaction::findOrFail($id);
|
|
$before_status = $transaction->status;
|
|
$business_id = request()->session()->get('user.business_id');
|
|
$enable_product_editing = $request->session()->get('business.enable_editing_product_from_purchase');
|
|
|
|
$transaction_before = $transaction->replicate();
|
|
|
|
$currency_details = $this->transactionUtil->purchaseCurrencyDetails($business_id);
|
|
|
|
$update_data = $request->only(['ref_no', 'status', 'contact_id',
|
|
'transaction_date', 'total_before_tax',
|
|
'discount_type', 'discount_amount', 'tax_id',
|
|
'tax_amount', 'shipping_details',
|
|
'shipping_charges', 'final_total',
|
|
'additional_notes', 'exchange_rate', 'pay_term_number', 'pay_term_type', 'purchase_order_ids', ]);
|
|
|
|
$exchange_rate = $update_data['exchange_rate'];
|
|
|
|
//Reverse exchage rate and save
|
|
//$update_data['exchange_rate'] = number_format(1 / $update_data['exchange_rate'], 2);
|
|
|
|
$update_data['transaction_date'] = $this->productUtil->uf_date($update_data['transaction_date'], true);
|
|
|
|
//unformat input values
|
|
$update_data['total_before_tax'] = $this->productUtil->num_uf($update_data['total_before_tax'], $currency_details) * $exchange_rate;
|
|
|
|
// If discount type is fixed them multiply by exchange rate, else don't
|
|
if ($update_data['discount_type'] == 'fixed') {
|
|
$update_data['discount_amount'] = $this->productUtil->num_uf($update_data['discount_amount'], $currency_details) * $exchange_rate;
|
|
} elseif ($update_data['discount_type'] == 'percentage') {
|
|
$update_data['discount_amount'] = $this->productUtil->num_uf($update_data['discount_amount'], $currency_details);
|
|
} else {
|
|
$update_data['discount_amount'] = 0;
|
|
}
|
|
|
|
$update_data['tax_amount'] = $this->productUtil->num_uf($update_data['tax_amount'], $currency_details) * $exchange_rate;
|
|
$update_data['shipping_charges'] = $this->productUtil->num_uf($update_data['shipping_charges'], $currency_details) * $exchange_rate;
|
|
$update_data['final_total'] = $this->productUtil->num_uf($update_data['final_total'], $currency_details) * $exchange_rate;
|
|
//unformat input values ends
|
|
|
|
$update_data['custom_field_1'] = $request->input('custom_field_1', null);
|
|
$update_data['custom_field_2'] = $request->input('custom_field_2', null);
|
|
$update_data['custom_field_3'] = $request->input('custom_field_3', null);
|
|
$update_data['custom_field_4'] = $request->input('custom_field_4', null);
|
|
|
|
$update_data['shipping_custom_field_1'] = $request->input('shipping_custom_field_1', null);
|
|
$update_data['shipping_custom_field_2'] = $request->input('shipping_custom_field_2', null);
|
|
$update_data['shipping_custom_field_3'] = $request->input('shipping_custom_field_3', null);
|
|
$update_data['shipping_custom_field_4'] = $request->input('shipping_custom_field_4', null);
|
|
$update_data['shipping_custom_field_5'] = $request->input('shipping_custom_field_5', null);
|
|
|
|
//upload document
|
|
$document_name = $this->transactionUtil->uploadFile($request, 'document', 'documents');
|
|
if (! empty($document_name)) {
|
|
$update_data['document'] = $document_name;
|
|
}
|
|
|
|
$purchase_order_ids = $transaction->purchase_order_ids ?? [];
|
|
|
|
$update_data['additional_expense_key_1'] = $request->input('additional_expense_key_1');
|
|
$update_data['additional_expense_key_2'] = $request->input('additional_expense_key_2');
|
|
$update_data['additional_expense_key_3'] = $request->input('additional_expense_key_3');
|
|
$update_data['additional_expense_key_4'] = $request->input('additional_expense_key_4');
|
|
|
|
$update_data['additional_expense_value_1'] = $request->input('additional_expense_value_1') != '' ? $this->productUtil->num_uf($request->input('additional_expense_value_1'), $currency_details) * $exchange_rate : 0;
|
|
$update_data['additional_expense_value_2'] = $request->input('additional_expense_value_2') != '' ? $this->productUtil->num_uf($request->input('additional_expense_value_2'), $currency_details) * $exchange_rate : 0;
|
|
$update_data['additional_expense_value_3'] = $request->input('additional_expense_value_3') != '' ? $this->productUtil->num_uf($request->input('additional_expense_value_3'), $currency_details) * $exchange_rate : 0;
|
|
$update_data['additional_expense_value_4'] = $request->input('additional_expense_value_4') != '' ? $this->productUtil->num_uf($request->input('additional_expense_value_4'), $currency_details) * $exchange_rate : 0;
|
|
|
|
DB::beginTransaction();
|
|
|
|
//update transaction
|
|
$transaction->update($update_data);
|
|
|
|
//Update transaction payment status
|
|
$payment_status = $this->transactionUtil->updatePaymentStatus($transaction->id);
|
|
$transaction->payment_status = $payment_status;
|
|
|
|
$purchases = $request->input('purchases');
|
|
|
|
$delete_purchase_lines = $this->productUtil->createOrUpdatePurchaseLines($transaction, $purchases, $currency_details, $enable_product_editing, $before_status);
|
|
|
|
//Update mapping of purchase & Sell.
|
|
$this->transactionUtil->adjustMappingPurchaseSellAfterEditingPurchase($before_status, $transaction, $delete_purchase_lines);
|
|
|
|
//Adjust stock over selling if found
|
|
$this->productUtil->adjustStockOverSelling($transaction);
|
|
|
|
$new_purchase_order_ids = $transaction->purchase_order_ids ?? [];
|
|
$purchase_order_ids = array_merge($purchase_order_ids, $new_purchase_order_ids);
|
|
if (! empty($purchase_order_ids)) {
|
|
$this->transactionUtil->updatePurchaseOrderStatus($purchase_order_ids);
|
|
}
|
|
|
|
$this->transactionUtil->activityLog($transaction, 'edited', $transaction_before);
|
|
|
|
PurchaseCreatedOrModified::dispatch($transaction);
|
|
|
|
DB::commit();
|
|
|
|
$output = ['success' => 1,
|
|
'msg' => __('purchase.purchase_update_success'),
|
|
];
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
\Log::emergency('File:'.$e->getFile().'Line:'.$e->getLine().'Message:'.$e->getMessage());
|
|
|
|
$output = ['success' => 0,
|
|
'msg' => $e->getMessage(),
|
|
];
|
|
|
|
return back()->with('status', $output);
|
|
}
|
|
|
|
return redirect('purchases')->with('status', $output);
|
|
}
|
|
|
|
/**
|
|
* Remove the specified resource from storage.
|
|
*
|
|
* @param int $id
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function destroy($id)
|
|
{
|
|
if (! auth()->user()->can('purchase.delete')) {
|
|
abort(403, 'Unauthorized action.');
|
|
}
|
|
|
|
try {
|
|
if (request()->ajax()) {
|
|
$business_id = request()->session()->get('user.business_id');
|
|
|
|
//Check if return exist then not allowed
|
|
if ($this->transactionUtil->isReturnExist($id)) {
|
|
$output = [
|
|
'success' => false,
|
|
'msg' => __('lang_v1.return_exist'),
|
|
];
|
|
|
|
return $output;
|
|
}
|
|
|
|
$transaction = Transaction::where('id', $id)
|
|
->where('business_id', $business_id)
|
|
->with(['purchase_lines'])
|
|
->first();
|
|
|
|
//Check if lot numbers from the purchase is selected in sale
|
|
if (request()->session()->get('business.enable_lot_number') == 1 && $this->transactionUtil->isLotUsed($transaction)) {
|
|
$output = [
|
|
'success' => false,
|
|
'msg' => __('lang_v1.lot_numbers_are_used_in_sale'),
|
|
];
|
|
|
|
return $output;
|
|
}
|
|
|
|
$delete_purchase_lines = $transaction->purchase_lines;
|
|
DB::beginTransaction();
|
|
|
|
$log_properities = [
|
|
'id' => $transaction->id,
|
|
'ref_no' => $transaction->ref_no,
|
|
];
|
|
$this->transactionUtil->activityLog($transaction, 'purchase_deleted', $log_properities);
|
|
|
|
$transaction_status = $transaction->status;
|
|
if ($transaction_status != 'received') {
|
|
$transaction->delete();
|
|
} else {
|
|
//Delete purchase lines first
|
|
$delete_purchase_line_ids = [];
|
|
foreach ($delete_purchase_lines as $purchase_line) {
|
|
$delete_purchase_line_ids[] = $purchase_line->id;
|
|
$this->productUtil->decreaseProductQuantity(
|
|
$purchase_line->product_id,
|
|
$purchase_line->variation_id,
|
|
$transaction->location_id,
|
|
$purchase_line->quantity
|
|
);
|
|
}
|
|
PurchaseLine::where('transaction_id', $transaction->id)
|
|
->whereIn('id', $delete_purchase_line_ids)
|
|
->delete();
|
|
|
|
//Update mapping of purchase & Sell.
|
|
$this->transactionUtil->adjustMappingPurchaseSellAfterEditingPurchase($transaction_status, $transaction, $delete_purchase_lines);
|
|
}
|
|
|
|
//Delete Transaction
|
|
$transaction->delete();
|
|
|
|
//Delete account transactions
|
|
AccountTransaction::where('transaction_id', $id)->delete();
|
|
|
|
PurchaseCreatedOrModified::dispatch($transaction, true);
|
|
|
|
DB::commit();
|
|
|
|
$output = ['success' => true,
|
|
'msg' => __('lang_v1.purchase_delete_success'),
|
|
];
|
|
}
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
\Log::emergency('File:'.$e->getFile().'Line:'.$e->getLine().'Message:'.$e->getMessage());
|
|
|
|
$output = ['success' => false,
|
|
'msg' => $e->getMessage(),
|
|
];
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Retrieves supliers list.
|
|
*
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function getSuppliers()
|
|
{
|
|
if (request()->ajax()) {
|
|
$term = request()->q;
|
|
if (empty($term)) {
|
|
return json_encode([]);
|
|
}
|
|
|
|
$business_id = request()->session()->get('user.business_id');
|
|
$user_id = request()->session()->get('user.id');
|
|
|
|
$query = Contact::where('business_id', $business_id)
|
|
->active();
|
|
|
|
$suppliers = $query->where(function ($query) use ($term) {
|
|
$query->where('name', 'like', '%'.$term.'%')
|
|
->orWhere('supplier_business_name', 'like', '%'.$term.'%')
|
|
->orWhere('contacts.contact_id', 'like', '%'.$term.'%');
|
|
})
|
|
->select(
|
|
'contacts.id',
|
|
DB::raw('IF(name="", supplier_business_name, name) as text'),
|
|
'supplier_business_name as business_name',
|
|
'contacts.mobile',
|
|
'contacts.address_line_1',
|
|
'contacts.address_line_2',
|
|
'contacts.city',
|
|
'contacts.state',
|
|
'contacts.country',
|
|
'contacts.zip_code',
|
|
'contacts.contact_id',
|
|
'contacts.pay_term_type',
|
|
'contacts.pay_term_number',
|
|
'contacts.balance'
|
|
)
|
|
->onlySuppliers()
|
|
->get();
|
|
|
|
return json_encode($suppliers);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves products list.
|
|
*
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function getProducts()
|
|
{
|
|
if (request()->ajax()) {
|
|
$term = request()->term;
|
|
|
|
$check_enable_stock = true;
|
|
if (isset(request()->check_enable_stock)) {
|
|
$check_enable_stock = filter_var(request()->check_enable_stock, FILTER_VALIDATE_BOOLEAN);
|
|
}
|
|
|
|
$only_variations = false;
|
|
if (isset(request()->only_variations)) {
|
|
$only_variations = filter_var(request()->only_variations, FILTER_VALIDATE_BOOLEAN);
|
|
}
|
|
|
|
if (empty($term)) {
|
|
return json_encode([]);
|
|
}
|
|
|
|
$business_id = request()->session()->get('user.business_id');
|
|
$q = Product::leftJoin(
|
|
'variations',
|
|
'products.id',
|
|
'=',
|
|
'variations.product_id'
|
|
)
|
|
->where(function ($query) use ($term) {
|
|
$query->where('products.name', 'like', '%'.$term.'%');
|
|
$query->orWhere('sku', 'like', '%'.$term.'%');
|
|
$query->orWhere('sub_sku', 'like', '%'.$term.'%');
|
|
})
|
|
->active()
|
|
->where('business_id', $business_id)
|
|
->whereNull('variations.deleted_at')
|
|
->select(
|
|
'products.id as product_id',
|
|
'products.name',
|
|
'products.type',
|
|
// 'products.sku as sku',
|
|
'variations.id as variation_id',
|
|
'variations.name as variation',
|
|
'variations.sub_sku as sub_sku'
|
|
)
|
|
->groupBy('variation_id');
|
|
|
|
if ($check_enable_stock) {
|
|
$q->where('enable_stock', 1);
|
|
}
|
|
if (! empty(request()->location_id)) {
|
|
$q->ForLocation(request()->location_id);
|
|
}
|
|
$products = $q->get();
|
|
|
|
$products_array = [];
|
|
foreach ($products as $product) {
|
|
$products_array[$product->product_id]['name'] = $product->name;
|
|
$products_array[$product->product_id]['sku'] = $product->sub_sku;
|
|
$products_array[$product->product_id]['type'] = $product->type;
|
|
$products_array[$product->product_id]['variations'][]
|
|
= [
|
|
'variation_id' => $product->variation_id,
|
|
'variation_name' => $product->variation,
|
|
'sub_sku' => $product->sub_sku,
|
|
];
|
|
}
|
|
|
|
$result = [];
|
|
$i = 1;
|
|
$no_of_records = $products->count();
|
|
if (! empty($products_array)) {
|
|
foreach ($products_array as $key => $value) {
|
|
if ($no_of_records > 1 && $value['type'] != 'single' && ! $only_variations) {
|
|
$result[] = ['id' => $i,
|
|
'text' => $value['name'].' - '.$value['sku'],
|
|
'variation_id' => 0,
|
|
'product_id' => $key,
|
|
];
|
|
}
|
|
$name = $value['name'];
|
|
foreach ($value['variations'] as $variation) {
|
|
$text = $name;
|
|
if ($value['type'] == 'variable') {
|
|
$text = $text.' ('.$variation['variation_name'].')';
|
|
}
|
|
$i++;
|
|
$result[] = ['id' => $i,
|
|
'text' => $text.' - '.$variation['sub_sku'],
|
|
'product_id' => $key,
|
|
'variation_id' => $variation['variation_id'],
|
|
];
|
|
}
|
|
$i++;
|
|
}
|
|
}
|
|
|
|
return json_encode($result);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Retrieves products list.
|
|
*
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function getPurchaseEntryRow(Request $request)
|
|
{
|
|
if (request()->ajax()) {
|
|
$product_id = $request->input('product_id');
|
|
$variation_id = $request->input('variation_id');
|
|
$business_id = request()->session()->get('user.business_id');
|
|
$location_id = $request->input('location_id');
|
|
$is_purchase_order = $request->has('is_purchase_order');
|
|
$supplier_id = $request->input('supplier_id');
|
|
|
|
$hide_tax = 'hide';
|
|
if ($request->session()->get('business.enable_inline_tax') == 1) {
|
|
$hide_tax = '';
|
|
}
|
|
|
|
$currency_details = $this->transactionUtil->purchaseCurrencyDetails($business_id);
|
|
|
|
if (! empty($product_id)) {
|
|
$row_count = $request->input('row_count');
|
|
$product = Product::where('id', $product_id)
|
|
->with(['unit', 'second_unit'])
|
|
->first();
|
|
|
|
$sub_units = $this->productUtil->getSubUnits($business_id, $product->unit->id, false, $product_id);
|
|
|
|
$query = Variation::where('product_id', $product_id)
|
|
->with([
|
|
'product_variation',
|
|
'variation_location_details' => function ($q) use ($location_id) {
|
|
$q->where('location_id', $location_id);
|
|
},
|
|
]);
|
|
if ($variation_id !== '0') {
|
|
$query->where('id', $variation_id);
|
|
}
|
|
|
|
$variations = $query->get();
|
|
$taxes = TaxRate::where('business_id', $business_id)
|
|
->ExcludeForTaxGroup()
|
|
->get();
|
|
|
|
$last_purchase_line = $this->getLastPurchaseLine($variation_id, $location_id, $supplier_id);
|
|
|
|
return view('purchase.partials.purchase_entry_row')
|
|
->with(compact(
|
|
'product',
|
|
'variations',
|
|
'row_count',
|
|
'variation_id',
|
|
'taxes',
|
|
'currency_details',
|
|
'hide_tax',
|
|
'sub_units',
|
|
'is_purchase_order',
|
|
'last_purchase_line'
|
|
));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Finds last purchase line of a variation for the supplier for a location
|
|
*/
|
|
private function getLastPurchaseLine($variation_id, $location_id, $supplier_id = null)
|
|
{
|
|
$query = PurchaseLine::join('transactions as t', 'purchase_lines.transaction_id',
|
|
'=', 't.id')
|
|
->where('t.location_id', $location_id)
|
|
->where('t.type', 'purchase')
|
|
->where('t.status', 'received')
|
|
->where('purchase_lines.variation_id', $variation_id);
|
|
|
|
if (! empty($supplier_id)) {
|
|
$query = $query->where('t.contact_id', '=', $supplier_id);
|
|
}
|
|
$purchase_line = $query->orderBy('transaction_date', 'desc')
|
|
->select('purchase_lines.*')
|
|
->first();
|
|
|
|
return $purchase_line;
|
|
}
|
|
|
|
public function importPurchaseProducts(Request $request)
|
|
{
|
|
try {
|
|
$file = $request->file('file');
|
|
|
|
$parsed_array = Excel::toArray([], $file);
|
|
//Remove header row
|
|
$imported_data = array_splice($parsed_array[0], 1);
|
|
|
|
$business_id = $request->session()->get('user.business_id');
|
|
$location_id = $request->input('location_id');
|
|
$row_count = $request->input('row_count');
|
|
|
|
$formatted_data = [];
|
|
$row_index = 0;
|
|
$error_msg = '';
|
|
foreach ($imported_data as $key => $value) {
|
|
$row_index = $key + 1;
|
|
$temp_array = [];
|
|
|
|
if (! empty($value[0])) {
|
|
$variation = Variation::where('sub_sku', trim($value[0]))
|
|
->join('products', 'products.id', '=', 'variations.product_id')
|
|
->where('products.business_id', $business_id)
|
|
->with([
|
|
'product_variation',
|
|
'variation_location_details' => function ($q) use ($location_id) {
|
|
$q->where('location_id', $location_id);
|
|
},
|
|
])
|
|
->select('variations.*')
|
|
->first();
|
|
$temp_array['variation'] = $variation;
|
|
|
|
if (empty($variation)) {
|
|
$error_msg = __('lang_v1.product_not_found_exception', ['row' => $row_index, 'sku' => $value[0]]);
|
|
break;
|
|
}
|
|
|
|
$product = Product::where('id', $variation->product_id)
|
|
->where('business_id', $business_id)
|
|
->with(['unit'])
|
|
->first();
|
|
|
|
if (empty($product)) {
|
|
$error_msg = __('lang_v1.product_not_found_exception', ['row' => $row_index, 'sku' => $value[0]]);
|
|
break;
|
|
}
|
|
|
|
$temp_array['product'] = $product;
|
|
|
|
$sub_units = $this->productUtil->getSubUnits($business_id, $product->unit->id, false, $product->id);
|
|
|
|
$temp_array['sub_units'] = $sub_units;
|
|
} else {
|
|
$error_msg = __('lang_v1.product_not_found_exception', ['row' => $row_index, 'sku' => $value[0]]);
|
|
break;
|
|
}
|
|
|
|
if (! empty($value[0])) {
|
|
$temp_array['quantity'] = $value[1];
|
|
} else {
|
|
$error_msg = __('lang_v1.quantity_required', ['row' => $row_index]);
|
|
break;
|
|
}
|
|
|
|
$temp_array['unit_cost_before_discount'] = ! empty($value[2]) ? $value[2] : $variation->default_purchase_price;
|
|
$temp_array['discount_percent'] = ! empty($value[3]) ? $value[3] : 0;
|
|
|
|
$tax_id = null;
|
|
|
|
if (! empty($value[4])) {
|
|
$tax_name = trim($value[4]);
|
|
$tax = TaxRate::where('business_id', $business_id)
|
|
->where('name', 'like', "%{$tax_name}%")
|
|
->first();
|
|
|
|
$tax_id = $tax->id ?? $tax_id;
|
|
}
|
|
|
|
$temp_array['tax_id'] = $tax_id;
|
|
$temp_array['lot_number'] = ! empty($value[5]) ? $value[5] : null;
|
|
$temp_array['mfg_date'] = ! empty($value[6]) ? $this->productUtil->format_date($value[6]) : null;
|
|
$temp_array['exp_date'] = ! empty($value[7]) ? $this->productUtil->format_date($value[7]) : null;
|
|
|
|
$formatted_data[] = $temp_array;
|
|
}
|
|
|
|
if (! empty($error_msg)) {
|
|
return [
|
|
'success' => false,
|
|
'msg' => $error_msg,
|
|
];
|
|
}
|
|
|
|
$hide_tax = 'hide';
|
|
if ($request->session()->get('business.enable_inline_tax') == 1) {
|
|
$hide_tax = '';
|
|
}
|
|
|
|
$taxes = TaxRate::where('business_id', $business_id)
|
|
->ExcludeForTaxGroup()
|
|
->get();
|
|
|
|
$currency_details = $this->transactionUtil->purchaseCurrencyDetails($business_id);
|
|
|
|
$html = view('purchase.partials.imported_purchase_product_rows')
|
|
->with(compact('formatted_data', 'taxes', 'currency_details', 'hide_tax', 'row_count'))->render();
|
|
|
|
return [
|
|
'success' => true,
|
|
'msg' => __('lang_v.imported'),
|
|
'html' => $html,
|
|
];
|
|
} catch (\Exception $e) {
|
|
return [
|
|
'success' => false,
|
|
'msg' => $e->getMessage(),
|
|
];
|
|
}
|
|
}
|
|
|
|
public function getPurchaseOrderLines($purchase_order_id)
|
|
{
|
|
$business_id = request()->session()->get('user.business_id');
|
|
|
|
$purchase_order = Transaction::where('business_id', $business_id)
|
|
->where('type', 'purchase_order')
|
|
->with(['purchase_lines', 'purchase_lines.variations',
|
|
'purchase_lines.product', 'purchase_lines.product.unit', 'purchase_lines.variations.product_variation', ])
|
|
->findOrFail($purchase_order_id);
|
|
|
|
$taxes = TaxRate::where('business_id', $business_id)
|
|
->ExcludeForTaxGroup()
|
|
->get();
|
|
|
|
$sub_units_array = [];
|
|
foreach ($purchase_order->purchase_lines as $pl) {
|
|
$sub_units_array[$pl->id] = $this->productUtil->getSubUnits($business_id, $pl->product->unit->id, false, $pl->product_id);
|
|
}
|
|
$hide_tax = request()->session()->get('business.enable_inline_tax') == 1 ? '' : 'hide';
|
|
$currency_details = $this->transactionUtil->purchaseCurrencyDetails($business_id);
|
|
$row_count = request()->input('row_count');
|
|
|
|
$html = view('purchase.partials.purchase_order_lines')
|
|
->with(compact(
|
|
'purchase_order',
|
|
'taxes',
|
|
'hide_tax',
|
|
'currency_details',
|
|
'row_count',
|
|
'sub_units_array'
|
|
))->render();
|
|
|
|
return [
|
|
'html' => $html,
|
|
'po' => $purchase_order,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Checks if ref_number and supplier combination already exists.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function checkRefNumber(Request $request)
|
|
{
|
|
$business_id = $request->session()->get('user.business_id');
|
|
$contact_id = $request->input('contact_id');
|
|
$ref_no = $request->input('ref_no');
|
|
$purchase_id = $request->input('purchase_id');
|
|
|
|
$count = 0;
|
|
if (! empty($contact_id) && ! empty($ref_no)) {
|
|
//check in transactions table
|
|
$query = Transaction::where('business_id', $business_id)
|
|
->where('ref_no', $ref_no)
|
|
->where('contact_id', $contact_id);
|
|
if (! empty($purchase_id)) {
|
|
$query->where('id', '!=', $purchase_id);
|
|
}
|
|
$count = $query->count();
|
|
}
|
|
if ($count == 0) {
|
|
echo 'true';
|
|
exit;
|
|
} else {
|
|
echo 'false';
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if ref_number and supplier combination already exists.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function printInvoice($id)
|
|
{
|
|
try {
|
|
$business_id = request()->session()->get('user.business_id');
|
|
$taxes = TaxRate::where('business_id', $business_id)
|
|
->pluck('name', 'id');
|
|
$purchase = Transaction::where('business_id', $business_id)
|
|
->where('id', $id)
|
|
->with(
|
|
'contact',
|
|
'purchase_lines',
|
|
'purchase_lines.product',
|
|
'purchase_lines.variations',
|
|
'purchase_lines.variations.product_variation',
|
|
'location',
|
|
'payment_lines'
|
|
)
|
|
->first();
|
|
$payment_methods = $this->productUtil->payment_types(null, false, $business_id);
|
|
|
|
// new line add from show function to show purchase text
|
|
$purchase_taxes = [];
|
|
if (! empty($purchase->tax)) {
|
|
if ($purchase->tax->is_tax_group) {
|
|
$purchase_taxes = $this->transactionUtil->sumGroupTaxDetails($this->transactionUtil->groupTaxDetails($purchase->tax, $purchase->tax_amount));
|
|
} else {
|
|
$purchase_taxes[$purchase->tax->name] = $purchase->tax_amount;
|
|
}
|
|
}
|
|
|
|
|
|
foreach ($purchase->purchase_lines as $key => $value) {
|
|
if (! empty($value->sub_unit_id)) {
|
|
$formated_purchase_line = $this->productUtil->changePurchaseLineUnit($value, $business_id);
|
|
$purchase->purchase_lines[$key] = $formated_purchase_line;
|
|
}
|
|
}
|
|
|
|
//Purchase orders
|
|
$purchase_order_nos = '';
|
|
$purchase_order_dates = '';
|
|
if (! empty($purchase->purchase_order_ids)) {
|
|
$purchase_orders = Transaction::find($purchase->purchase_order_ids);
|
|
|
|
$purchase_order_nos = implode(', ', $purchase_orders->pluck('ref_no')->toArray());
|
|
$order_dates = [];
|
|
foreach ($purchase_orders as $purchase_order) {
|
|
$order_dates[] = $this->transactionUtil->format_date($purchase_order->transaction_date, true);
|
|
}
|
|
$purchase_order_dates = implode(', ', $order_dates);
|
|
}
|
|
|
|
$output = ['success' => 1, 'receipt' => [], 'print_title' => $purchase->ref_no];
|
|
$output['receipt']['html_content'] = view('purchase.partials.show_details', compact('taxes', 'purchase', 'payment_methods', 'purchase_order_nos', 'purchase_order_dates', 'purchase_taxes'))->render();
|
|
} catch (\Exception $e) {
|
|
\Log::emergency('File:'.$e->getFile().'Line:'.$e->getLine().'Message:'.$e->getMessage());
|
|
|
|
$output = ['success' => 0,
|
|
'msg' => __('messages.something_went_wrong'),
|
|
];
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Update purchase status.
|
|
*
|
|
* @param \Illuminate\Http\Request $request
|
|
* @return \Illuminate\Http\Response
|
|
*/
|
|
public function updateStatus(Request $request)
|
|
{
|
|
if (! auth()->user()->can('purchase.update') && ! auth()->user()->can('purchase.update_status')) {
|
|
abort(403, 'Unauthorized action.');
|
|
}
|
|
//Check if the transaction can be edited or not.
|
|
$edit_days = request()->session()->get('business.transaction_edit_days');
|
|
if (! $this->transactionUtil->canBeEdited($request->input('purchase_id'), $edit_days)) {
|
|
return ['success' => 0,
|
|
'msg' => __('messages.transaction_edit_not_allowed', ['days' => $edit_days]), ];
|
|
}
|
|
|
|
try {
|
|
$business_id = request()->session()->get('user.business_id');
|
|
|
|
$transaction = Transaction::where('business_id', $business_id)
|
|
->where('type', 'purchase')
|
|
->with(['purchase_lines'])
|
|
->findOrFail($request->input('purchase_id'));
|
|
|
|
$before_status = $transaction->status;
|
|
|
|
$update_data['status'] = $request->input('status');
|
|
|
|
DB::beginTransaction();
|
|
|
|
//update transaction
|
|
$transaction->update($update_data);
|
|
|
|
$currency_details = $this->transactionUtil->purchaseCurrencyDetails($business_id);
|
|
foreach ($transaction->purchase_lines as $purchase_line) {
|
|
$this->productUtil->updateProductStock($before_status, $transaction, $purchase_line->product_id, $purchase_line->variation_id, $purchase_line->quantity, $purchase_line->quantity, $currency_details);
|
|
}
|
|
|
|
//Update mapping of purchase & Sell.
|
|
$this->transactionUtil->adjustMappingPurchaseSellAfterEditingPurchase($before_status, $transaction, null);
|
|
|
|
//Adjust stock over selling if found
|
|
$this->productUtil->adjustStockOverSelling($transaction);
|
|
|
|
DB::commit();
|
|
|
|
$output = ['success' => 1,
|
|
'msg' => __('purchase.purchase_update_success'),
|
|
];
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
\Log::emergency('File:'.$e->getFile().'Line:'.$e->getLine().'Message:'.$e->getMessage());
|
|
|
|
$output = ['success' => 0,
|
|
'msg' => $e->getMessage(),
|
|
];
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
}
|