/**
  * Creates data provider instance with search query applied
  *
  * @param array $params
  *
  * @return ActiveDataProvider
  */
 public function search($params)
 {
     $query = TransactionDetail::find();
     $dataProvider = new ActiveDataProvider(['query' => $query]);
     $this->load($params);
     if (!$this->validate()) {
         // uncomment the following line if you do not want to return any records when validation fails
         // $query->where('0=1');
         return $dataProvider;
     }
     $query->andFilterWhere(['trans_service_id' => $this->trans_service_id, 'trans_qty' => $this->trans_qty, 'price' => $this->price]);
     $query->andFilterWhere(['like', 'trans_id', $this->trans_id]);
     return $dataProvider;
 }
 /**
  * Display product stock's movement
  *
  * @param skip, take
  * @return Response
  */
 public function card($id = null)
 {
     $varian = \App\Models\Varian::id($id);
     $detail = \App\Models\TransactionDetail::varianid($id)->stockmovement(true);
     if (Input::has('search')) {
         $search = Input::get('search');
         foreach ($search as $key => $value) {
             switch (strtolower($key)) {
                 case 'ondate':
                     if (is_array($value)) {
                         $balance = \App\Models\Varian::id($id)->TransactionLogChangedAt($value[0]);
                         $prev_date = $value[0];
                         $detail = $detail->TransactionLogChangedAt($value);
                         $varian = $varian->TransactionLogChangedAt($value[1]);
                     } else {
                         $detail = $detail->TransactionLogChangedAt($value);
                         $varian = $varian->TransactionLogChangedAt($value);
                     }
                     break;
                 default:
                     # code...
                     break;
             }
         }
     }
     if (!$varian->first()) {
         return new JSend('error', (array) Input::all(), 'ID Tidak valid.');
     }
     $varian = $varian->with(['product'])->first()->toArray();
     if (isset($balance)) {
         $balance = $balance->first();
         $balance_old[] = ['ref' => 'Balance', 'varian_id' => $id, 'transact_at' => Carbon::parse($prev_date)->format('Y-m-d H:i:s'), 'stock_in' => $balance['inventory_stock'], 'stock_out' => 0];
         $detail_old = $detail->get()->toArray();
         if (!empty($detail_old)) {
             $varian['details'] = array_merge($balance_old, $detail_old);
         } else {
             $varian['details'] = $balance_old;
         }
     } else {
         $varian['details'] = $detail->get()->toArray();
     }
     return new JSend('success', (array) $varian);
 }
 /**
  * Display purchased product by customer
  *
  * @return Response
  */
 public function purchased($user_id = 0)
 {
     $purchased_prods = [];
     //1. get purchased item
     $purchased = \App\Models\TransactionDetail::TransactionSellOn(['paid', 'packed', 'shipping', 'delivered'])->where('transactions.user_id', $user_id)->groupby('varian_id')->with(['varian'])->get()->toArray();
     foreach ($purchased as $key => $value) {
         //2. get product id
         $purchased_prods[] = $value['varian']['product_id'];
     }
     $productids = array_unique($purchased_prods);
     $result = \App\Models\Product::id($productids)->sellable(true);
     $count = count($result->get(['id']));
     if (Input::has('skip')) {
         $skip = Input::get('skip');
         $result = $result->skip($skip);
     }
     if (Input::has('take')) {
         $take = Input::get('take');
         $result = $result->take($take);
     }
     $result = $result->with(['varians'])->get()->toArray();
     return new JSend('success', (array) ['count' => $count, 'data' => $result]);
 }
 /** 
  * observe transaction detail event saving
  * 1. Check transactions tatus
  * 2. Check duplicate varian
  * 3. act, accept or refuse
  * 
  * @param $model
  * @return bool
  */
 public function saving($model)
 {
     $errors = new MessageBag();
     //1. check transactions tatus
     if ($model->sale()->count() && $model->sale->status != 'cart' && count($model->getDirty())) {
         $errors->add('Detail', 'Tidak dapat menambahkan item baru. Silahkan membuat nota baru.');
     }
     //2. Check duplicate varian
     if (is_null($model->id)) {
         $id = 0;
     } else {
         $id = $model->id;
     }
     $check_prev_trans = \App\Models\TransactionDetail::transactionid($model->transaction_id)->varianid($model->varian_id)->notid($id)->first();
     if ($check_prev_trans) {
         $errors->add('Detail', 'Tidak dapat menyimpan 2 record untuk varian id yang sama.');
     }
     if ($errors->count()) {
         $model['errors'] = $errors;
         return false;
     }
     return true;
 }
 /**
  * Finds the TransactionDetail model based on its primary key value.
  * If the model is not found, a 404 HTTP exception will be thrown.
  * @param string $trans_id
  * @param string $trans_service_id
  * @return TransactionDetail the loaded model
  * @throws NotFoundHttpException if the model cannot be found
  */
 protected function findModel($trans_id, $trans_service_id)
 {
     if (($model = TransactionDetail::findOne(['trans_id' => $trans_id, 'trans_service_id' => $trans_service_id])) !== null) {
         return $model;
     } else {
         throw new NotFoundHttpException('The requested page does not exist.');
     }
 }
 /**
  * @return \yii\db\ActiveQuery
  */
 public function getTransactionDetails()
 {
     return $this->hasMany(TransactionDetail::className(), ['trans_service_id' => 'service_id']);
 }
 public function get_data_detail($id)
 {
     $transaction = Transaction::where('transactions.id', '=', $id)->join('customers', 'transactions.customer_id', '=', 'customers.id')->join('users', 'transactions.user_id', '=', 'users.id')->select('transactions.*', 'customers.name', 'customers.address', 'customers.phone', 'customers.membership', 'users.name as username')->firstOrFail();
     $list_detail = TransactionDetail::where('transaction_details.transaction_id', '=', $id)->join('packages', 'transaction_details.package_id', '=', 'packages.id')->select('transaction_details.*', 'transaction_details.id as detail_id', 'packages.*')->paginate(25);
     $data = ['transaction' => $transaction, 'detail_transaction' => $list_detail];
     return $data;
 }
示例#8
0
 /**
  * Display store customer order
  *
  * @return Response
  */
 public function store()
 {
     if (!Input::has('order')) {
         return new JSend('error', (array) Input::all(), 'Tidak ada data order.');
     }
     $errors = new MessageBag();
     $order = Input::get('order');
     DB::beginTransaction();
     $user_id = Request::route()[2]['user_id'];
     $order = Input::get('order');
     if (is_null($order['id'])) {
         $is_new = true;
     } else {
         $is_new = false;
     }
     if (isset($order['voucher_code'])) {
         //a. check if voucher code is voucher
         $voucher = \App\Models\Voucher::code($order['voucher_code'])->type(['free_shipping_cost', 'debit_point'])->first();
         if (!$voucher) {
             //b. check if voucher is referral
             $voucher_data = \App\Models\Referral::code($order['voucher_code'])->first();
             if (!$voucher_data) {
                 $voucher_data = \App\Models\Voucher::code($order['voucher_code'])->type('promo_referral')->ondate('now')->first();
             }
             if (!$voucher_data) {
                 return new JSend('error', (array) Input::all(), ['Voucher tidak valid.']);
             } elseif ($voucher_data->quota <= 0) {
                 $errors->add('Redeem', 'Quota referral sudah habis.');
             } else {
                 $store = \App\Models\StoreSetting::type('voucher_point_expired')->Ondate('now')->first();
                 if ($store) {
                     $expired_at = new Carbon($store->value);
                 } else {
                     $expired_at = new Carbon('+ 3 months');
                 }
                 //if validator passed, save voucher
                 if ($voucher_data['type'] == 'referral') {
                     $reference_id = $voucher_data['user_id'];
                     $reference_type = 'App\\Models\\User';
                 } else {
                     $reference_id = $voucher_data['id'];
                     $reference_type = 'App\\Models\\Voucher';
                 }
                 $point = ['user_id' => $user_id, 'reference_id' => $reference_id, 'reference_type' => $reference_type, 'expired_at' => $expired_at->format('Y-m-d H:i:s')];
                 $point_data = new \App\Models\PointLog();
                 $point_data->fill($point);
                 if (!$point_data->save()) {
                     $errors->add('Redeem', $point_data->getError());
                 }
             }
         } else {
             $order['voucher_id'] = $voucher['id'];
         }
     }
     if (isset($order['voucher_id']) && $order['voucher_id'] == 0) {
         $order['voucher_id'] = '';
     }
     $order_rules = ['voucher_id' => 'exists:tmp_vouchers,id'];
     //1a. Get original data
     $order_data = \App\Models\Sale::findornew($order['id']);
     //1b. Validate Basic Order Parameter
     $validator = Validator::make($order, $order_rules);
     if (!$validator->passes() && !$errors->count()) {
         $errors->add('Sale', $validator->errors());
     } elseif (!$errors->count()) {
         //if validator passed, save order
         $order_data = $order_data->fill(['user_id' => $user_id, 'voucher_id' => isset($order['voucher_id']) ? $order['voucher_id'] : '0']);
         if (!$order_data->save()) {
             $errors->add('Sale', $order_data->getError());
         }
     }
     //2. Validate Order Detail Parameter
     if (!$errors->count() && isset($order['transactiondetails']) && is_array($order['transactiondetails'])) {
         $detail_current_ids = [];
         foreach ($order['transactiondetails'] as $key => $value) {
             if (!$errors->count() && isset($value['quantity']) && $value['quantity'] > 0) {
                 $detail_data = \App\Models\TransactionDetail::findornew($value['id']);
                 $detail_rules = ['transaction_id' => 'exists:transactions,id|' . ($is_new ? '' : 'in:' . $order_data['id']), 'varian_id' => 'required|exists:varians,id', 'quantity' => 'required|numeric', 'price' => 'required|numeric', 'discount' => 'numeric'];
                 $validator = Validator::make($value, $detail_rules);
                 //if there was detail and validator false
                 if (!$validator->passes()) {
                     $errors->add('Detail', $validator->errors());
                 } else {
                     $check_prev_trans = \App\Models\TransactionDetail::transactionid($order_data['id'])->varianid($value['varian_id'])->first();
                     if ($check_prev_trans) {
                         $detail_data = $check_prev_trans;
                     }
                     $value['transaction_id'] = $order_data['id'];
                     $detail_data = $detail_data->fill($value);
                     if (!$detail_data->save()) {
                         $errors->add('Detail', $detail_data->getError());
                     } else {
                         $detail_current_ids[] = $detail_data['id'];
                     }
                 }
             }
         }
         //if there was no error, check if there were things need to be delete
         if (!$errors->count()) {
             $details = \App\Models\TransactionDetail::transactionid($order['id'])->get(['id'])->toArray();
             $detail_should_be_ids = [];
             foreach ($details as $key => $value) {
                 $detail_should_be_ids[] = $value['id'];
             }
             $difference_detail_ids = array_diff($detail_should_be_ids, $detail_current_ids);
             if ($difference_detail_ids) {
                 foreach ($difference_detail_ids as $key => $value) {
                     $detail_data = \App\Models\TransactionDetail::find($value);
                     if (!$detail_data->delete()) {
                         $errors->add('Detail', $detail_data->getError());
                     }
                 }
             }
         }
     }
     //3. Validate Order Detail Parameter
     if (!$errors->count() && isset($order['transactionextensions']) && is_array($order['transactionextensions'])) {
         $extend_current_ids = [];
         foreach ($order['transactionextensions'] as $key => $value) {
             if (!$errors->count()) {
                 $extend_data = \App\Models\TransactionExtension::findornew($value['id']);
                 $extend_rules = ['transaction_id' => 'exists:transactions,id|' . ($is_new ? '' : 'in:' . $order_data['id']), 'product_extension_id' => 'required|exists:product_extensions,id', 'price' => 'required|numeric'];
                 $validator = Validator::make($value, $extend_rules);
                 //if there was extend and validator false
                 if (!$validator->passes()) {
                     $errors->add('Extend', $validator->errors());
                 } else {
                     $check_prev_trans = \App\Models\TransactionExtension::transactionid($order_data['id'])->productextensionid($value['product_extension_id'])->first();
                     if ($check_prev_trans) {
                         $extend_data = $check_prev_trans;
                     }
                     $value['transaction_id'] = $order_data['id'];
                     $extend_data = $extend_data->fill($value);
                     if (!$extend_data->save()) {
                         $errors->add('Extend', $extend_data->getError());
                     } else {
                         $extend_current_ids[] = $extend_data['id'];
                     }
                 }
             }
         }
         //if there was no error, check if there were things need to be delete
         if (!$errors->count()) {
             $extends = \App\Models\TransactionExtension::transactionid($order['id'])->get(['id'])->toArray();
             $extend_should_be_ids = [];
             foreach ($extends as $key => $value) {
                 $extend_should_be_ids[] = $value['id'];
             }
             $difference_extend_ids = array_diff($extend_should_be_ids, $extend_current_ids);
             if ($difference_extend_ids) {
                 foreach ($difference_extend_ids as $key => $value) {
                     $extend_data = \App\Models\TransactionExtension::find($value);
                     if (!$extend_data->delete()) {
                         $errors->add('Extend', $extend_data->getError());
                     }
                 }
             }
         }
     }
     //4. Check if need to save address
     if (!$errors->count() && isset($order['shipment']['address'])) {
         $address_data = \App\Models\Address::findornew($order['shipment']['address']['id']);
         $address_rules = ['owner_id' => 'exists:users,id|' . ($is_new ? '' : 'in:' . $user_id), 'owner_type' => $is_new ? '' : 'in:App\\Models\\Customer', 'phone' => 'required|max:255', 'address' => 'required', 'zipcode' => 'required|max:255'];
         $validator = Validator::make($order['shipment']['address'], $address_rules);
         //4a. save address
         //if there was address and validator false
         if (!$validator->passes()) {
             $errors->add('Sale', $validator->errors());
         } else {
             //if validator passed, save address
             $order['shipment']['address']['owner_id'] = $user_id;
             $order['shipment']['address']['owner_type'] = 'App\\Models\\Customer';
             $address_data = $address_data->fill($order['shipment']['address']);
             if (!$address_data->save()) {
                 $errors->add('Sale', $address_data->getError());
             }
         }
     }
     //4b. save shipment
     if (!$errors->count() && isset($order['shipment'])) {
         if ($order_data->shipment()->count()) {
             $shipment_data = \App\Models\Shipment::findorfail($order_data->shipment->id);
         } else {
             $shipment_data = \App\Models\Shipment::findornew($order['shipment']['id']);
         }
         $shipment_rules = ['courier_id' => 'required|exists:couriers,id', 'receiver_name' => 'required|max:255'];
         $validator = Validator::make($order['shipment'], $shipment_rules);
         //4c. save shipment
         //if there was shipment and validator false
         if (!$validator->passes()) {
             $errors->add('Sale', $validator->errors());
         } else {
             //if validator passed, save shipment
             $order['shipment']['transaction_id'] = $order['id'];
             if (isset($address_data['id'])) {
                 $order['shipment']['address_id'] = $address_data['id'];
             }
             $shipment_data = $shipment_data->fill($order['shipment']);
             if (!$shipment_data->save()) {
                 $errors->add('Sale', $shipment_data->getError());
             }
         }
     }
     //5. update status
     if (!$errors->count() && isset($order['status']) && $order_data['status'] != $order['status']) {
         //3a. check cart price and product current  price
         if ($order['status'] == 'wait') {
             foreach ($order_data['transactiondetails'] as $key => $value) {
                 $discount = $value['varian']['product']['promo_price'] == 0 ? 0 : $value['varian']['product']['price'] - $value['varian']['product']['promo_price'];
                 if ($value['price'] != $value['varian']['product']['price'] || $value['discount'] != $discount) {
                     $errors->add('Price', 'Harga item ' . $value['varian']['product']['name'] . ' telah berubah sejak ' . $value['varian']['product']['price_start'] . '. Silahkan update keranjang Anda.');
                 }
             }
             foreach ($order_data['transactionextensions'] as $key => $value) {
                 if ($value['price'] != $value['productextension']['price']) {
                     $errors->add('Price', 'Biaya ' . $value['productextension']['name'] . ' telah berubah sejak ' . $value['productextension']['updated_at'] . '. Silahkan update keranjang Anda.');
                 }
                 if (!$value['productextension']['is_active']) {
                     $errors->add('Active', $value['productextension']['name'] . ' telah di non aktif kan sejak ' . $value['productextension']['updated_at'] . '. Silahkan update keranjang Anda.');
                 }
             }
         }
         if (!$errors->count()) {
             $log_data = new \App\Models\TransactionLog();
             $log_data = $log_data->fill(['status' => $order['status'], 'transaction_id' => $order_data['id']]);
             if (!$log_data->save()) {
                 $errors->add('Log', $log_data->getError());
             }
         }
     }
     if ($errors->count()) {
         DB::rollback();
         return new JSend('error', (array) Input::all(), $errors);
     }
     DB::commit();
     $final_order = \App\Models\Sale::userid($user_id)->id($order_data['id'])->status(['cart', 'wait', 'payment_process', 'canceled', 'paid', 'shipping', 'packed', 'delivered'])->with(['payment', 'orderlogs', 'transactiondetails', 'transactiondetails.varian', 'transactiondetails.varian.product', 'shipment', 'shipment.courier', 'shipment.address', 'voucher', 'user', 'transactionextensions', 'transactionextensions.productextension'])->first()->toArray();
     return new JSend('success', (array) $final_order);
 }
示例#9
0
 /**
  * Store a purchase
  *
  * 1. Save Purchase
  * 2. Save Transaction Detail
  * 3. Save Transaction Log
  * 
  * @return Response
  */
 public function store()
 {
     if (!Input::has('purchase')) {
         return new JSend('error', (array) Input::all(), 'Tidak ada data purchase.');
     }
     $errors = new MessageBag();
     DB::beginTransaction();
     //1. Validate Purchase Parameter
     $purchase = Input::get('purchase');
     if (is_null($purchase['id'])) {
         $is_new = true;
     } else {
         $is_new = false;
     }
     $purchase_rules = ['supplier_id' => 'required|exists:suppliers,id'];
     //1a. Get original data
     $purchase_data = \App\Models\Purchase::findornew($purchase['id']);
     //1b. Validate Basic Purchase Parameter
     $validator = Validator::make($purchase, $purchase_rules);
     if (!$validator->passes()) {
         $errors->add('Purchase', $validator->errors());
     } else {
         //if validator passed, save purchase
         $purchase_data = $purchase_data->fill(['supplier_id' => $purchase['supplier_id'], 'type' => 'buy', 'transact_at' => isset($purchase['transact_at']) ? $purchase['transact_at'] : '']);
         if (!$purchase_data->save()) {
             $errors->add('Purchase', $purchase_data->getError());
         }
     }
     //2. Validate Purchase Detail Parameter
     if (!$errors->count() && isset($purchase['transactiondetails']) && is_array($purchase['transactiondetails'])) {
         $detail_current_ids = [];
         foreach ($purchase['transactiondetails'] as $key => $value) {
             if (!$errors->count()) {
                 $detail_data = \App\Models\TransactionDetail::findornew($value['id']);
                 $detail_rules = ['transaction_id' => 'exists:transactions,id|' . ($is_new ? '' : 'in:' . $purchase_data['id']), 'varian_id' => 'required|exists:varians,id', 'quantity' => 'required|numeric', 'price' => 'required|numeric', 'discount' => 'numeric'];
                 $validator = Validator::make($value, $detail_rules);
                 //if there was detail and validator false
                 if (!$validator->passes()) {
                     $errors->add('Detail', $validator->errors());
                 } else {
                     $value['transaction_id'] = $purchase_data['id'];
                     $detail_data = $detail_data->fill($value);
                     if (!$detail_data->save()) {
                         $errors->add('Detail', $detail_data->getError());
                     } else {
                         $detail_current_ids[] = $detail_data['id'];
                     }
                 }
             }
         }
         //if there was no error, check if there were things need to be delete
         if (!$errors->count()) {
             $details = \App\Models\TransactionDetail::transactionid($purchase['id'])->get(['id'])->toArray();
             $detail_should_be_ids = [];
             foreach ($details as $key => $value) {
                 $detail_should_be_ids[] = $value['id'];
             }
             $difference_detail_ids = array_diff($detail_should_be_ids, $detail_current_ids);
             if ($difference_detail_ids) {
                 foreach ($difference_detail_ids as $key => $value) {
                     $detail_data = \App\Models\TransactionDetail::find($value);
                     if (!$detail_data->delete()) {
                         $errors->add('Detail', $detail_data->getError());
                     }
                 }
             }
         }
     }
     //3. Validate Purchase Status Parameter
     if (!$errors->count() && isset($purchase['transactionlogs']) && is_array($purchase['transactionlogs'])) {
         $log_current_ids = [];
         foreach ($purchase['transactionlogs'] as $key => $value) {
             if (!$errors->count()) {
                 $log_data = \App\Models\TransactionLog::findornew($value['id']);
                 $log_rules = ['transaction_id' => 'exists:transactions,id|' . ($is_new ? '' : 'in:' . $purchase_data['id']), 'status' => 'required|max:255|in:cart,wait,paid,packed,shipping,delivered,canceled,abandoned'];
                 $validator = Validator::make($value, $log_rules);
                 //if there was log and validator false
                 if (!$validator->passes()) {
                     $errors->add('Log', $validator->errors());
                 } else {
                     $value['transaction_id'] = $purchase_data['id'];
                     $log_data = $log_data->fill($value);
                     if (!$log_data->save()) {
                         $errors->add('Log', $log_data->getError());
                     } else {
                         $log_current_ids[] = $log_data['id'];
                     }
                 }
             }
         }
         //if there was no error, check if there were things need to be delete
         if (!$errors->count()) {
             $logs = \App\Models\TransactionLog::transactionid($purchase['id'])->get(['id'])->toArray();
             $log_should_be_ids = [];
             foreach ($logs as $key => $value) {
                 $log_should_be_ids[] = $value['id'];
             }
             $difference_log_ids = array_diff($log_should_be_ids, $log_current_ids);
             if ($difference_log_ids) {
                 foreach ($difference_log_ids as $key => $value) {
                     $log_data = \App\Models\TransactionLog::find($value);
                     if (!$log_data->delete()) {
                         $errors->add('Log', $log_data->getError());
                     }
                 }
             }
         }
     }
     //4. Compare status
     if (isset($purchase['status']) && $purchase_data['status'] != $purchase['status']) {
         $log_rules = ['transaction_id' => 'exists:transactions,id|' . ($is_new ? '' : 'in:' . $purchase_data['id']), 'status' => 'required|max:255|in:cart,wait,paid,packed,shipping,delivered,canceled,abandoned'];
         $validator = Validator::make($purchase, $log_rules);
         //if there was log and validator false
         if (!$validator->passes()) {
             $errors->add('Log', 'Status Tidak Valid.');
         } else {
             $log_data = new \App\Models\TransactionLog();
             $log_data = $log_data->fill(['status' => $purchase['status'], 'transaction_id' => $purchase_data['id']]);
             if (!$log_data->save()) {
                 $errors->add('Log', $log_data->getError());
             }
         }
     }
     if ($errors->count()) {
         DB::rollback();
         return new JSend('error', (array) Input::all(), $errors);
     }
     DB::commit();
     $final_purchase = \App\Models\Purchase::id($purchase_data['id'])->with(['transactionlogs', 'supplier', 'transactiondetails', 'transactiondetails.varian', 'transactiondetails.varian.product'])->first()->toArray();
     return new JSend('success', (array) $final_purchase);
 }
示例#10
0
 /**
  * boot
  * observing model
  *
  */
 public static function boot()
 {
     parent::boot();
     TransactionDetail::observe(new TransactionDetailObserver());
 }
示例#11
0
 /**
  * update 1st version
  *
  * @return void
  * @author 
  **/
 public function pointexpire($id)
 {
     $queue = new Queue();
     $pending = $queue->find($id);
     $parameters = json_decode($pending->parameter, true);
     $messages = json_decode($pending->message, true);
     $errors = new MessageBag();
     //check point expire on that day that havent get cut by transaction (or even left over)
     $points = PointLog::debit(true)->onactive([Carbon::parse($parameters['on'])->startOfDay()->format('Y-m-d H:i:s'), Carbon::parse($parameters['on'])->endOfDay()->format('Y-m-d H:i:s')])->haventgetcut(true)->with(['user'])->get()->toArray();
     foreach ($points as $idx => $point) {
         //1. Check tag/category viewed
         $stat = \App\Models\StatUserView::userid($point['user_id'])->statabletype(['App\\Models\\Category', 'App\\Models\\Tag'])->get(['statable_id'])->toArray();
         //1b. Get slugs
         $slugs = [];
         $purchased_prods = [];
         $purchased_varians = [];
         foreach ($stat as $key => $value) {
             $slugs[] = \App\Models\Cluster::find($value['statable_id'])['slug'];
         }
         $purchased = \App\Models\TransactionDetail::TransactionSellOn(['paid', 'packed', 'shipping', 'delivered'])->where('transactions.user_id', $point['user_id'])->groupby('varian_id')->with(['varian', 'varian.product', 'varian.product.clusters'])->get()->toArray();
         foreach ($purchased as $key => $value) {
             //2. Check tag/category purchased
             foreach ($value['varian']['product']['clusters'] as $key2 => $value2) {
                 $slugs[] = $value2['slug'];
             }
             $purchased_prods[] = $value['varian']['product_id'];
             $purchased_varians[] = $value['varian']['size'];
         }
         //2a. get slug of category/tag
         //2b. get product id
         //2c. get varian size
         $slug = array_unique($slugs);
         $productids = array_unique($purchased_prods);
         $variansize = array_unique($purchased_varians);
         $result = \App\Models\Product::sellable(true);
         if (!empty($slug)) {
             $result = $result->clustersslug($slug);
         }
         if (!empty($productids)) {
             $result = $result->notid($productids);
         }
         if (!empty($variansize)) {
             $result = $result->variansize($variansize);
         }
         $product = $result->orderby('price', 'desc')->take(4)->get()->toArray();
         $data = ['point' => $point, 'balin' => $parameters['store'], 'product' => $product];
         //send mail
         Mail::send('mail.' . $parameters['template'] . '.crm.point', ['data' => $data], function ($message) use($point, $parameters) {
             $message->to($point['user']['email'], $point['user']['name'])->subject(strtoupper($parameters['template']) . ' - POINT REMINDER');
         });
         $pnumber = $pending->process_number + 1;
         $messages['message'][$pnumber] = 'Sukses Mengirim Email ' . (isset($point['user']['name']) ? $point['user']['name'] : '');
         $pending->fill(['process_number' => $pnumber, 'message' => json_encode($messages)]);
         $pending->save();
     }
     return true;
 }