843 lines
33 KiB
PHP
843 lines
33 KiB
PHP
<?php
|
|
|
|
namespace App\Repositories\Pos;
|
|
|
|
use App\Models\Bank;
|
|
use App\Models\Survey;
|
|
use App\Models\PosInvoice;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Carbon\Carbon;
|
|
use App\Models\Items;
|
|
use App\Models\Location;
|
|
use App\Models\Role;
|
|
use App\Models\Sales;
|
|
use App\Models\Voucher;
|
|
use App\Models\VoucherClaim;
|
|
use App\Models\AffiliatorItem;
|
|
use App\Models\VoucherEvent;
|
|
use App\Models\AffiliatorItemCode;
|
|
use App\Models\Incentive;
|
|
use App\Helpers\AutoNumbering;
|
|
use App\Models\XenditLink;
|
|
use App\Models\ItemReference;
|
|
use App\Models\LuckyWheel;
|
|
use App\Models\SerialNumberDetail;
|
|
use App\Models\SerialNumberLog;
|
|
use App\Notifications\Crm\SurveyBroadcast;
|
|
use App\Repositories\Crm\SurveyRepository;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
class InvoiceRepository
|
|
{
|
|
|
|
var $surveyRepository;
|
|
|
|
public function __construct(SurveyRepository $surveyRepository){
|
|
$this->surveyRepository = $surveyRepository;
|
|
}
|
|
|
|
public function getList(array $params = [], $all = false)
|
|
{
|
|
$user = auth()->user();
|
|
$location_id = @$user->employee->location_id;
|
|
|
|
$sortColumn = [
|
|
'number' => 'pos_invoices.number',
|
|
'time' => 'pos_invoices.time',
|
|
'total' => 'pos_invoices.total',
|
|
'location.name' => 'locations.name',
|
|
'customer' => 'customers.name',
|
|
'sales.name' => 'sales.name',
|
|
'sales2.name' => 'sales.name',
|
|
'user.name' => 'users.name'
|
|
];
|
|
|
|
$limit = @$params["limit"] ? (int) @$params["limit"] : 10;
|
|
$sortColumn = @$params["sort"]["column"] ? $sortColumn[$params["sort"]["column"]] : "pos_invoices.id";
|
|
$sortDir = @$params["sort"]["dir"] ? $params["sort"]["dir"] : "desc";
|
|
|
|
$results = PosInvoice::selectRaw("
|
|
pos_invoices.*,
|
|
CASE WHEN a.first_transaction is not null THEN 1 ELSE 0 END as new_customer,
|
|
CASE WHEN (a.first_transaction IS NOT NULL AND customers.number NOT ILIKE 'CAG%') OR customers.number = 'NONAME' THEN 'online' ELSE 'offline' END as type"
|
|
)
|
|
->leftJoin(DB::raw("(select min(pos_invoices.id) as first_transaction from pos_invoices group by customer_id) as a"), 'a.first_transaction', 'pos_invoices.id')
|
|
->leftJoin('transactions', 'transactions.invoice_id', 'pos_invoices.id')
|
|
->leftJoin('locations', 'locations.id', 'pos_invoices.location_id')
|
|
->leftJoin('customers', 'customers.id', 'pos_invoices.customer_id')
|
|
->leftJoin('users', 'users.id', 'pos_invoices.user_id')
|
|
->leftJoin('sales', 'sales.id', 'pos_invoices.sales_id')
|
|
->leftJoin('sales as sales2', 'sales2.id', 'pos_invoices.sales2_id')
|
|
->when(@$params["search"], function ($query) use ($params) {
|
|
$query->where(function ($query) use ($params) {
|
|
$query->where("pos_invoices.number", "ilike", "%" . $params["search"] . "%")
|
|
->orWhere("sales.name", "ilike", "%" . $params["search"] . "%")
|
|
->orWhere("sales2.name", "ilike", "%" . $params["search"] . "%")
|
|
->orWhere("users.name", "ilike", "%" . $params["search"] . "%")
|
|
->orWhere("customers.name", "ilike", "%" . $params["search"] . "%")
|
|
->orWhere("customers.phone", "ilike", "%" . $params["search"] . "%");
|
|
/* ->orWhereExists(function($subquery) use ($params) {
|
|
$subquery->select(DB::raw(1))
|
|
->from('pos_invoice_details')
|
|
->leftJoin('items', 'pos_invoice_details.item_id', 'items.id')
|
|
->leftJoin('item_variants', 'item_variants.id', 'pos_invoice_details.item_variant_id')
|
|
->leftJoin('item_reference', 'item_reference.id', 'pos_invoice_details.item_reference_id')
|
|
->whereColumn('pos_invoice_details.invoice_id', 'pos_invoices.id')
|
|
->where(function($q) use ($params) {
|
|
$q->where('item_reference.number', 'ilike', '%' . $params['search'] . '%')
|
|
->orWhere('items.number', 'ilike', '%' . $params['search'] . '%')
|
|
->orWhere('items.name', 'ilike', '%' . $params['search'] . '%')
|
|
->orWhere('item_variants.description', 'ilike', '%' . $params['search'] . '%')
|
|
->orWhere('item_variants.code', 'ilike', '%' . $params['search'] . '%');
|
|
});
|
|
}); */
|
|
});
|
|
})
|
|
->when(!$all, function ($query) use ($location_id) {
|
|
$query->where("pos_invoices.location_id", $location_id);
|
|
})
|
|
->when(@$params['active'], function($query) {
|
|
$query->whereNull('canceled_at');
|
|
})
|
|
->when(@$params['filter'], function ($query) use ($params) {
|
|
foreach ($params['filter'] as $filter) {
|
|
if ($filter['column'] == 'start') {
|
|
$query->whereDate("pos_invoices.time", ">=", $filter["query"]);
|
|
} else if ($filter['column'] == 'end') {
|
|
$query->whereDate("pos_invoices.time", "<=", $filter["query"]);
|
|
} else if ($filter['column'] == 'sync') {
|
|
if ($filter['query'] == 'BERHASIL') {
|
|
$query->whereNotNull('pos_invoices.sync_at');
|
|
}
|
|
|
|
if ($filter['query'] == 'GAGAL') {
|
|
$query->whereNull('pos_invoices.sync_at')
|
|
->whereNotNull('pos_invoices.sync_log');
|
|
}
|
|
} else if ($filter['column'] == 'payment_method') {
|
|
$query->whereRaw("EXISTS (SELECT id FROM pos_invoice_payments WHERE invoice_id = pos_invoices.id AND method = '" . $filter['query'] . "' AND amount > 0)");
|
|
} else {
|
|
$query->where('pos_invoices.' . $filter['column'], $filter['query']);
|
|
}
|
|
}
|
|
})
|
|
->orderBy($sortColumn, $sortDir)
|
|
->paginate($limit);
|
|
return $results;
|
|
}
|
|
|
|
public function getUnPosted()
|
|
{
|
|
return PosInvoice::whereNull("sync_at")
|
|
->whereNull("canceled_at")
|
|
->take(1000)->get();
|
|
}
|
|
|
|
public function createFromOnline($model)
|
|
{
|
|
DB::beginTransaction();
|
|
try{
|
|
$sales = Sales::where("name","ECOMMERCE")->first();
|
|
$user = auth()->user();
|
|
$posInvoice = PosInvoice::find((int) $model->invoice_id);
|
|
if ($posInvoice)
|
|
return;
|
|
|
|
$location = $model->location;
|
|
$auto = new AutoNumbering([
|
|
"type" => "POS",
|
|
"prefix" => str_replace(" ", "", $location->code),
|
|
"location_id" => $location->id,
|
|
"pad" => 12
|
|
]);
|
|
$number = $auto->getCurrent();
|
|
|
|
$invoice = new PosInvoice([
|
|
"number" => $number,
|
|
"user_id" => $user->id,
|
|
"customer_id" => $model->customer_id,
|
|
"time" => $model->time,
|
|
"location_id" => $location->id,
|
|
"sales_id" => (int) @$sales->id,
|
|
"note" => @$model->note,
|
|
"subtotal" => $model->subtotal,
|
|
"voucher" => 0,
|
|
"discount" => 0,
|
|
"tax" => 0,
|
|
"total" => $model->subtotal + $model->shipping_price,
|
|
"vouchers" => "",
|
|
"note_internal" => $model->number,
|
|
]);
|
|
$invoice->save();
|
|
$model->invoice_id = $invoice->id;
|
|
$model->save();
|
|
|
|
foreach ($model->details as $row) {
|
|
$invoice->details()->create([
|
|
'item_reference_id' => $row->item_reference_id,
|
|
'item_id' => $row->item_id,
|
|
'item_variant_id' => $row->item_variant_id,
|
|
'note' => '',
|
|
'qty' => $row->qty,
|
|
'unit_price'=> $row->unit_price,
|
|
'unit'=> $row->unit,
|
|
'reference'=> $row->reference->number,
|
|
'discount'=> (int) @$row->discount,
|
|
'vat'=> 0,
|
|
'total'=> $row->total,
|
|
'unit_cost'=> $row->unit_cost
|
|
]);
|
|
}
|
|
|
|
// find biaya expedisi + asuransi
|
|
$item = ItemReference::where("number","9CBYEXPDAS")->first();
|
|
|
|
if ($model->shipping_price && $item){
|
|
$invoice->details()->create([
|
|
'item_reference_id' => $item->id,
|
|
'item_id' => $item->item_id,
|
|
'item_variant_id' => $item->item_variant_id,
|
|
'note' => $model->courier_company." ".$model->courier_type,
|
|
'qty' => 1,
|
|
'unit_price' => $model->shipping_price,
|
|
'unit' => 'PCS',
|
|
'reference' => $item->number,
|
|
'discount' => 0,
|
|
'vat' => 0,
|
|
'total'=> $model->shipping_price,
|
|
'unit_cost'=> $model->shipping_price
|
|
]);
|
|
}
|
|
|
|
foreach ($model->payments as $row) {
|
|
|
|
if ($row->method_type == XenditLink::class){
|
|
if ($row->status == "PAID"){
|
|
|
|
$invoice->payments()->create([
|
|
"method" => "XENDIT",
|
|
"amount" => $row->amount,
|
|
"bank" => "XENDIT",
|
|
"card_number" => $row->method->uid,
|
|
"remarks" => @$row->method->payment_method." ".@$row->method->bank_code
|
|
]);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach($model->vouchers as $voucher){
|
|
|
|
$invoice->payments()->create([
|
|
"method" => "VOUCHER",
|
|
"amount" => $voucher->nominal,
|
|
"bank" => "VOUCHER",
|
|
"card_number" => $voucher->number,
|
|
"remarks" => ""
|
|
]);
|
|
}
|
|
$model->invoice_id = $invoice->id;
|
|
$model->save();
|
|
|
|
$survey = Survey::where("name","AFTER PURCHASE")->first();
|
|
if ($survey){
|
|
$data = [
|
|
"channel" => "pos",
|
|
"customer_id" => $invoice->customer_id,
|
|
"invoice_id" => $invoice->id
|
|
];
|
|
$this->surveyRepository->generateFeedback($survey, $data);
|
|
}
|
|
|
|
DB::commit();
|
|
|
|
return $invoice;
|
|
}catch(\Exception $e){
|
|
DB::rollback();
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
public function create(array $data)
|
|
{
|
|
return DB::transaction(function () use ($data) {
|
|
|
|
$numbering = (array) @DB::select("SELECT id, transaction, location_id, prefix, pad, current
|
|
FROM numbering
|
|
WHERE transaction = ? AND location_id = ?
|
|
FOR UPDATE
|
|
", ["POS", $data["location_id"]])[0];
|
|
|
|
$location = Location::findOrFail($data["location_id"]);
|
|
if ($numbering == null) {
|
|
$numbering = DB::table("numbering")->insert([
|
|
"transaction" => "POS",
|
|
"location_id" => $data["location_id"],
|
|
"prefix" => str_replace(" ", "", $location->code),
|
|
"pad" => 12,
|
|
"current" => 0
|
|
]);
|
|
|
|
$numbering = (array) DB::select("SELECT id, transaction, location_id, prefix, pad, current
|
|
FROM numbering
|
|
WHERE id = ?
|
|
FOR UPDATE
|
|
", [DB::getPdo()->lastInsertId()])[0];
|
|
}
|
|
|
|
if (Carbon::now()->gte("2024-01-22")) {
|
|
$prefix_number = $numbering["prefix"];
|
|
$next_number = $numbering["current"] + 1;
|
|
$pad_number = $numbering["pad"] - strlen($prefix_number);
|
|
$number = $prefix_number . str_pad($next_number, $pad_number, 0, STR_PAD_LEFT);
|
|
DB::statement("UPDATE numbering SET current = current+1 WHERE id = ?", [$numbering["id"]]);
|
|
} else {
|
|
$count = DB::select("select last_value from pos_invoices_id_seq")[0]->last_value;
|
|
$number = "POS" . str_pad($count + 1, 6, 0, STR_PAD_LEFT);
|
|
}
|
|
|
|
|
|
// $count = DB::select("select last_value from pos_invoices_id_seq")[0]->last_value;
|
|
$data["user_id"] = auth()->user()->id;
|
|
$data["voucher"] = (float) @$data["voucher"];
|
|
$data["time"] = Carbon::now();
|
|
$data["vouchers"] = @$data["vouchers"] ? implode(",", @$data["vouchers"]):"";
|
|
$data["number"] = $number;
|
|
$subtotal = (float) @$data["subtotal"];
|
|
$discount = (float) @$data["discount"];
|
|
$invoice = PosInvoice::create($data);
|
|
|
|
$exclude_item_points = [];
|
|
|
|
$i = 0;
|
|
foreach ($data["details"] as $row) {
|
|
$i++;
|
|
|
|
$item = Items::find($row["item_id"]);
|
|
$row["line_no"] = $i;
|
|
$row["unit_price"] = (float) @$row["unit_price"];
|
|
$row["total"] = (float) @$row["total"];
|
|
$row["discount"] = (float) @$row["discount"];
|
|
$row["vat"] = (float) @$row["vat"];
|
|
$row["unit_cost"] = @$item ? $item->unit_cost : 0;
|
|
$row["line_discount"] = @$row["discount"] * @$row["qty"];
|
|
$row["invoice_discount"] = $subtotal == 0 ? 0: ($row["total"] / $subtotal) * $discount;
|
|
$row["net_price"] = @$row['net_price'];
|
|
|
|
if (@$row['serial_number']){
|
|
$this->activateSerialNumber($invoice, @$row['serial_number'],[
|
|
"reference" => @$row["reference"],
|
|
"description" => @$row["description"],
|
|
"item_number" => @$row["item_number"],
|
|
"variant_code" => @$row["variant_code"],
|
|
"brand" => @$item->dimension->brand
|
|
]);
|
|
}
|
|
$row["pricelist_discount"] = @$row['pricelist_discount'];
|
|
if (strpos($item->name, "VOUCHER") > -1) {
|
|
$exp = $row["unit_price"] == 0 ? 3 : 6;
|
|
$row["reference"] = $this->issueVoucher($invoice, $item->name, $row["reference"], (float) @$row["qty"], $exp);
|
|
}
|
|
$invoice->details()->create($row);
|
|
}
|
|
|
|
// Handle DISCOUNT vouchers - save to pos_invoice_vouchers table
|
|
if (@$data["discount_vouchers"]) {
|
|
$this->useDiscountVoucher($invoice, $data["discount_vouchers"]);
|
|
}
|
|
|
|
// Handle SALE vouchers (payment vouchers) - legacy behavior
|
|
if (@$data["vouchers"])
|
|
$exclude_item_points = $this->useVoucher($invoice, $data["vouchers"]);
|
|
|
|
$this->checkPoint($invoice, $exclude_item_points);
|
|
|
|
foreach ($data["payments"] as $row) {
|
|
|
|
if ($row["amount"] <= 0)
|
|
continue;
|
|
|
|
$invoice->payments()->create($row);
|
|
|
|
if ($row['method'] == "POINT"){
|
|
|
|
DB::table("customer_points")
|
|
->insert([
|
|
"description" => "Use points for payment transaction " . $invoice->number,
|
|
"point" => ($row["amount"] / 1000) * -1,
|
|
"customer_id" => $invoice->customer_id,
|
|
"reference_id" => $invoice->id,
|
|
"reference_type" => get_class($invoice),
|
|
"created_at" => Carbon::now()
|
|
]);
|
|
}else if ($row['method'] == "VOUCHER"){
|
|
|
|
$voucher = Voucher::where('number', $row['card_number'])->first();
|
|
if ($voucher){
|
|
// Validate voucher is SALE type for payment method
|
|
if (($voucher->calculation_type ?? 'SALE') != 'SALE') {
|
|
throw ValidationException::withMessages([
|
|
"voucher" => "Voucher ini adalah Voucher Discount, bukan Voucher Belanja. Tidak bisa digunakan sebagai pembayaran."
|
|
]);
|
|
}
|
|
|
|
$voucher->used_at = Carbon::now();
|
|
$voucher->reference_used_id = $invoice->id;
|
|
$voucher->reference_used_type = get_class($invoice);
|
|
$voucher->save();
|
|
}
|
|
}
|
|
}
|
|
|
|
$luckyWheel = LuckyWheel::where("valid_at","<=", Carbon::now())
|
|
->where("expired_at",">=", Carbon::now())
|
|
->where(function($query) use ($location){
|
|
$query->whereNull("location_id")
|
|
->orWhere("location_id", @$location->id);
|
|
})
|
|
->where("min_sales_total","<", $invoice->total)
|
|
->first();
|
|
|
|
if ($luckyWheel){
|
|
$ticket_counts = $luckyWheel->tickets()->count();
|
|
if ($ticket_counts < $luckyWheel->max_ticket || $luckyWheel->max_ticket == -1){
|
|
$max_prize = $luckyWheel->max_prize;
|
|
$current_prize = $luckyWheel->gets()->whereNotNull("redeem_at")->sum("nominal");
|
|
|
|
// if ($max_prize > $current_prize){
|
|
|
|
// $ticket2 = $luckyWheel->tickets()->where("customer_id", $invoice->customer_id)->first();
|
|
// if ($ticket2 == null){
|
|
$ticket = $luckyWheel->tickets()->create([
|
|
"invoice_id" => $invoice->id,
|
|
"customer_id" => $invoice->customer_id,
|
|
"max_times" => 10
|
|
]);
|
|
// }
|
|
// }
|
|
}
|
|
}
|
|
|
|
$survey = Survey::where("name","AFTER PURCHASE")->first();
|
|
if ($survey){
|
|
$data = [
|
|
"channel" => "pos",
|
|
"customer_id" => $invoice->customer_id,
|
|
"invoice_id" => $invoice->id
|
|
];
|
|
$feedback = $this->surveyRepository->generateFeedback($survey, $data);
|
|
if ($feedback){
|
|
$notif = new SurveyBroadcast($feedback);
|
|
$invoice->customer->notify($notif);
|
|
}
|
|
}
|
|
|
|
return $invoice;
|
|
});
|
|
}
|
|
|
|
public function deactivateSerialNumber($invoice, $sn){
|
|
if (!@$sn)
|
|
return;
|
|
|
|
$arr = explode(",",$sn);
|
|
SerialNumberDetail::whereIn("number",$arr)->update([
|
|
"activated_at" => null
|
|
]);
|
|
SerialNumberLog::whereIn('number',$arr)->delete();
|
|
}
|
|
|
|
public function activateSerialNumber($invoice, $sn, $data){
|
|
if (!@$sn)
|
|
return;
|
|
|
|
$user = auth()->user();
|
|
$arr = explode(",",$sn);
|
|
foreach($arr as $row){
|
|
$snDetail = SerialNumberDetail::where("number",$row)->first();
|
|
if ($snDetail){
|
|
$snDetail->activated_at = Carbon::now();
|
|
$snDetail->activated_by = $user->id;
|
|
$snDetail->invoice_id = $invoice->id;
|
|
$snDetail->save();
|
|
}
|
|
|
|
$snLog = new SerialNumberLog;
|
|
$snLog->number = $row;
|
|
$snLog->activated_at = Carbon::now();
|
|
$snLog->reference_number = $data["reference"] ?? "";
|
|
$snLog->item_number = $data["item_number"] ?? "";
|
|
$snLog->variant_code = $data["variant_code"] ?? "";
|
|
$snLog->description = $data["description"] ?? "";
|
|
$snLog->brand = $data["brand"] ?? "";
|
|
$snLog->invoice_no = $invoice->number;
|
|
$snLog->save();
|
|
}
|
|
}
|
|
|
|
public function checkPoint($invoice, $item_ids)
|
|
{
|
|
|
|
$point = 0;
|
|
foreach ($invoice->details as $detail) {
|
|
$discount_items = DB::select("select apply_point from discounts left join discount_items on discounts.id = discount_items.discount_id
|
|
where item_reference_id = ? and valid_at <= NOW() and expired_at >= NOW() order by discounts.id desc", [@$detail->item_reference_id]);
|
|
|
|
$apply_point = count($discount_items) > 0 ? $discount_items[0]->apply_point : false;
|
|
$discount = (float) @$detail->discount;
|
|
$qty = (float) @$detail->qty;
|
|
|
|
if(!$apply_point) {
|
|
|
|
if ($discount > 0){
|
|
continue;
|
|
}
|
|
|
|
if ($detail->unit_price < $detail->item->net_price){
|
|
continue;
|
|
}
|
|
|
|
// skip is has discount from voucher
|
|
if (in_array($detail->item_reference_id, $item_ids)){
|
|
continue;
|
|
}
|
|
}
|
|
|
|
$rows = DB::select(
|
|
"select point from customer_point_rules WHERE item_reference_id = ? AND qty = ?",
|
|
[$detail->item_reference_id, $detail->qty]
|
|
);
|
|
if (count($rows)) {
|
|
|
|
$row_point = (float) @$rows[0]->point;
|
|
$detail->point = $row_point * $qty;
|
|
$detail->save();
|
|
$point += $detail->point;
|
|
} else {
|
|
|
|
$rows_general = DB::select(
|
|
"select point from customer_point_rules WHERE item_reference_id = ? AND (qty is null or qty = 0)",
|
|
[$detail->item_reference_id]
|
|
);
|
|
|
|
if (count($rows_general)) {
|
|
$row_point = (float) @$rows_general[0]->point;
|
|
$detail->point = $row_point * $qty;
|
|
$detail->save();
|
|
$point += $detail->point;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($point > 0 && $invoice->location->code != "IND") {
|
|
DB::table("customer_points")
|
|
->insert([
|
|
"description" => "Get points from transaction " . $invoice->number,
|
|
"point" => $point,
|
|
"customer_id" => $invoice->customer_id,
|
|
"reference_id" => $invoice->id,
|
|
"reference_type" => get_class($invoice),
|
|
"created_at" => Carbon::now()
|
|
]);
|
|
}
|
|
}
|
|
|
|
private function useVoucher($invoice, $vouchers)
|
|
{
|
|
$exclude_item_points = [];
|
|
$arr = explode(",", $vouchers);
|
|
foreach ($arr as $voucher) {
|
|
$item = Voucher::where("number", $voucher)->first();
|
|
if (!$item)
|
|
continue;
|
|
|
|
$item_id = $this->checkAffiliatorVoucher($invoice, $item);
|
|
if (count($item_id) > 0)
|
|
{
|
|
$exclude_item_points = array_merge($exclude_item_points, $item_id);
|
|
}
|
|
|
|
if (@$item->event){
|
|
$item_reference_ids = $item->event->items->pluck("id")->toArray();
|
|
$exclude_item_points = array_merge($exclude_item_points, $item_reference_ids);
|
|
}
|
|
|
|
$item->used_at = Carbon::now();
|
|
$item->reference_used_id = $invoice->id;
|
|
$item->reference_used_type = get_class($invoice);
|
|
$item->save();
|
|
}
|
|
|
|
return $exclude_item_points;
|
|
}
|
|
|
|
private function useDiscountVoucher($invoice, $discount_vouchers)
|
|
{
|
|
// discount_vouchers is an array of voucher codes
|
|
foreach ($discount_vouchers as $voucher_code) {
|
|
$voucher = Voucher::where("number", $voucher_code)->first();
|
|
if (!$voucher)
|
|
continue;
|
|
|
|
// Validate it's a DISCOUNT type voucher
|
|
if (($voucher->calculation_type ?? 'SALE') != 'DISCOUNT') {
|
|
throw ValidationException::withMessages([
|
|
"discount_voucher" => "Voucher {$voucher_code} bukan Voucher Discount."
|
|
]);
|
|
}
|
|
|
|
// Create pos_invoice_vouchers record
|
|
\App\Models\PosInvoiceVoucher::create([
|
|
'pos_invoice_id' => $invoice->id,
|
|
'voucher_id' => $voucher->id,
|
|
'nominal' => $voucher->nominal
|
|
]);
|
|
|
|
// Mark voucher as used
|
|
$voucher->used_at = Carbon::now();
|
|
$voucher->reference_used_id = $invoice->id;
|
|
$voucher->reference_used_type = get_class($invoice);
|
|
$voucher->save();
|
|
}
|
|
}
|
|
|
|
private function findDetail($invoice, $item_reference_ids){
|
|
return $invoice->details->filter(function($detail) use ($item_reference_ids){
|
|
return in_array($detail->item_reference_id , $item_reference_ids);
|
|
})->reduce(function($acc, $detail){
|
|
return $acc + ($detail->unit_price - $detail->unit_cost);
|
|
},0);
|
|
}
|
|
|
|
public function checkAffiliatorVoucher($invoice, $voucher){
|
|
if ($voucher->reference_issued_type != VoucherClaim::class){
|
|
return [];
|
|
}
|
|
$issued = $voucher->referenceIssued;
|
|
|
|
if ($issued->claimable_type != AffiliatorItemCode::class){
|
|
return [];
|
|
}
|
|
|
|
$claimable = $issued->claimable;
|
|
if ($claimable == null){
|
|
return [];
|
|
}
|
|
|
|
$affiliator = $claimable->affiliator;
|
|
|
|
if ($claimable->affiliatorItem != null){
|
|
$affiliatorItem = $claimable->affiliatorItem;
|
|
|
|
$itemReference = $affiliatorItem->item;
|
|
$item_reference_ids = [$itemReference->id];
|
|
$gross = $this->findDetail($invoice, $item_reference_ids);
|
|
$fee_nominal = $affiliatorItem->fee ? $affiliatorItem->fee : $gross * ($affiliator->fee_percentage/100);
|
|
|
|
}else if ($claimable->codeable_type == Affiliatoritem::class){
|
|
|
|
$affiliatorItem = $claimable->codeable;
|
|
$itemReference = $affiliatorItem->item;
|
|
$item_reference_ids = [$itemReference->id];
|
|
$gross = $this->findDetail($invoice, $item_reference_ids);
|
|
$fee_nominal = $affiliatorItem->fee ? $affiliatorItem->fee : $gross * ($affiliator->fee_percentage/100);
|
|
|
|
}else if ($claimable->codeable_type == VoucherEvent::class){
|
|
$voucherEvent = $claimable->codeable;
|
|
$item_reference_ids = $voucherEvent->items->pluck("id")->toArray();
|
|
$gross = $this->findDetail($invoice, $item_reference_ids);
|
|
$fee_nominal = $gross * ($affiliator->fee_percentage/100);
|
|
}else{
|
|
return [];
|
|
}
|
|
|
|
|
|
$incentive = new Incentive;
|
|
$incentive->fill([
|
|
"employee_id" => 0,
|
|
"person_id" => $affiliator->id,
|
|
"person_type" => get_class($affiliator),
|
|
"nominal" => $fee_nominal,
|
|
"date" => Carbon::now(),
|
|
"reference_id" => $voucher->id,
|
|
"reference_type" => get_class($voucher),
|
|
"status" => "OPEN"
|
|
]);
|
|
$incentive->save();
|
|
|
|
return $item_reference_ids;
|
|
}
|
|
|
|
private function generateVoucher($nominal)
|
|
{
|
|
$code = "BLJ";
|
|
if ($nominal == 2000000) {
|
|
$code = "2JT";
|
|
} else if ($nominal == 1000000) {
|
|
$code = "1JT";
|
|
} else if ($nominal == 1500000) {
|
|
$code = "1.5JT";
|
|
} else if ($nominal == 2500000) {
|
|
$code = "2.5JT";
|
|
} else if ($nominal == 500000) {
|
|
$code = "500RB";
|
|
} else if ($nominal == 750000) {
|
|
$code = "750RB";
|
|
} else if ($nominal == 250000) {
|
|
$code = "250RB";
|
|
} else if ($nominal == 100000) {
|
|
$code = "100RB";
|
|
} else if ($nominal == 50000) {
|
|
$code = "50RB";
|
|
} else if ($nominal == 3000000) {
|
|
$code = "3JT";
|
|
}
|
|
$voucher = null;
|
|
$iter = 0;
|
|
while ($voucher == null) {
|
|
$new_code = strtoupper("EV/" . $code . "/" . date("Y") . "/" . bin2hex(openssl_random_pseudo_bytes(3)));
|
|
$exists = Voucher::where("number", $new_code)->first();
|
|
$voucher = $exists ? null : $new_code;
|
|
}
|
|
return $voucher;
|
|
}
|
|
|
|
private function issueVoucher($invoice, $name, $vouchers, $qty, $exp)
|
|
{
|
|
|
|
$nominal = str_replace(".", "", $name);
|
|
preg_match("/[0-9]++/", $nominal, $match);
|
|
$nominal = (float) @$match[0];
|
|
|
|
$evoucher = true;
|
|
if ($vouchers == "") {
|
|
$arr = [];
|
|
for ($i = 0; $i < $qty; $i++) {
|
|
$arr[] = $this->generateVoucher($nominal);
|
|
}
|
|
|
|
$evoucher = true;
|
|
} else {
|
|
$arr = explode(",", $vouchers);
|
|
|
|
$evoucher = false;
|
|
}
|
|
foreach ($arr as $voucher) {
|
|
$voucher = trim($voucher);
|
|
$item = Voucher::where("number", $voucher)->firstOrNew();
|
|
$item->customer_id = $invoice->customer_id;
|
|
$item->evoucher = $evoucher;
|
|
$item->number = $voucher;
|
|
$item->nominal = $nominal;
|
|
$item->issued_at = Carbon::now();
|
|
$item->expired_at = Carbon::now()->addMonth($exp);
|
|
$item->reference_issued_id = $invoice->id;
|
|
$item->reference_issued_type = get_class($invoice);
|
|
$item->save();
|
|
}
|
|
|
|
return implode(",", $arr);
|
|
}
|
|
|
|
public function update(PosInvoice $invoice, array $data)
|
|
{
|
|
if (!$this->isAdmin()) {
|
|
$isCreatedToday = Carbon::now()->diffInMinutes(Carbon::parse($invoice->time)) <= (60 * 24);
|
|
if (!$isCreatedToday) {
|
|
return abort(403, 'hanya invoice yang belum 24 jam yang bisa di edit');
|
|
}
|
|
}
|
|
|
|
$data["vouchers"] = implode(",", $data["vouchers"]);
|
|
|
|
$invoice->update($data);
|
|
|
|
$ids = [];
|
|
foreach ($data["details"] as $row) {
|
|
$detail = $invoice->details()->find(@$row["id"]);
|
|
if (!$detail){
|
|
$item = Items::find($row["item_id"]);
|
|
$row["unit_price"] = (float) @$row["unit_price"];
|
|
$row["total"] = (float) @$row["total"];
|
|
$row["unit_cost"] = @$item ? $item->unit_cost : 0;
|
|
$detail = $invoice->details()->create($row);
|
|
}else{
|
|
$detail->update([
|
|
"qty" => $row["qty"],
|
|
"serial_number" => $row["serial_number"],
|
|
"total" => $row["total"],
|
|
"unit_price" => $row["unit_price"],
|
|
"discount" => $row["discount"],
|
|
]);
|
|
$item = $detail->item;
|
|
}
|
|
|
|
$this->deactivateSerialNumber($invoice, @$row['serial_number']);
|
|
|
|
$this->activateSerialNumber($invoice, @$row['serial_number'],[
|
|
"reference" => @$row["reference"],
|
|
"description" => @$row["description"],
|
|
"item_number" => @$row["item_number"],
|
|
"variant_code" => @$row["variant_code"],
|
|
"brand" => @$item->dimension->brand
|
|
]);
|
|
|
|
$ids[] = $detail->id;
|
|
}
|
|
$invoice->details()->whereNotIn("id",$ids)->delete($ids);
|
|
|
|
$ids = [];
|
|
foreach ($data["payments"] as $row) {
|
|
if ($row["amount"] <= 0)
|
|
continue;
|
|
|
|
$detail = $invoice->details()->find(@$row["id"]);
|
|
if (!$detail){
|
|
$detail = $invoice->payments()->create($row);
|
|
}else{
|
|
$detail->update($row);
|
|
}
|
|
$ids[] = $detail->id;
|
|
}
|
|
$invoice->payments()->whereNotIn("id",$ids)->delete();
|
|
|
|
return $invoice;
|
|
}
|
|
|
|
public function cancel(PosInvoice $item, $data)
|
|
{
|
|
$data["canceled_by"] = auth()->user()->id;
|
|
$data["canceled_at"] = Carbon::now();
|
|
$item->fill($data);
|
|
$item->save();
|
|
|
|
DB::table("customer_points")->where("reference_id", $item->id)
|
|
->where("reference_type", get_class($item))->delete();
|
|
|
|
DB::table("vouchers")
|
|
->where("reference_used_id", $item->id)
|
|
->where("reference_used_type", get_class($item))
|
|
->update([
|
|
"used_at" => null
|
|
]);
|
|
}
|
|
|
|
// public function delete(PosInvoice $item)
|
|
// {
|
|
// $item->delete();
|
|
// }
|
|
|
|
public function findBy($column, $value)
|
|
{
|
|
$item = PosInvoice::where($column, $value)->firstOrFail();
|
|
return $item;
|
|
}
|
|
|
|
public function isAdmin()
|
|
{
|
|
$admin = Role::where('name', 'ADMIN')->first();
|
|
$user = auth()->user();
|
|
|
|
return $user->role_id == $admin->id;
|
|
}
|
|
}
|