getMerchantList(['mchid' => ['gt',0]]); foreach ($items as $item) { $mchid = intval($item['mchid']); $this->mMerchantNames[$mchid] = !empty($item['company_name']) ? $item['company_name'] : $item['name']; } $items = Model('')->table('refill_provider,store') ->field('refill_provider.store_id,store.store_name,refill_provider.provider_id')->join('inner') ->on('store.store_id=refill_provider.store_id') ->where(['refill_provider.provider_id' => ['gt',0]]) ->select(); foreach ($items as $item) { $store_id = intval($item['store_id']); $this->mProviderNames[$store_id] = $item['store_name']; $this->mStoreidPID[$store_id] = intval($item['provider_id']); } $cfg_reader = function ($name, $field) { $data = rcache($name, 'refill-', $field); $val = $data[$field] ?? serialize([]); return unserialize($val); }; $this->mTimesTypes['system'] = [0 => ['order_time']]; $this->mTimesTypes['merchant'] = $cfg_reader('balance-cfg','merchant'); $this->mTimesTypes['provider'] = $cfg_reader('balance-cfg','provider'); } private function find_timetypes($type,$cid) { if(array_key_exists($type,$this->mTimesTypes)) { if(array_key_exists($cid,$this->mTimesTypes[$type])) { return $this->mTimesTypes[$type][$cid]; } } return []; } public function stat_all($end) { $mchids = function () { $result = []; foreach ($this->mMerchantNames as $mchid => $name) { $result[] = $mchid; } return $result; }; $store_ids = function () { $result = []; foreach ($this->mProviderNames as $storeid => $name) { $result[] = $storeid; } return $result; }; $types = ['system','merchant','provider']; foreach ($types as $type) { if ($type == 'system') { $cids = [0]; } elseif ($type == 'merchant') { $cids = $mchids(); } else { $cids = $store_ids(); } foreach ($cids as $cid) { $time_types = $this->find_timetypes($type,$cid); foreach ($time_types as $time_type) { [$parent_id,$start,$confirmed] = $this->find_parent($type, $cid, $time_type); if($start == $end) { Log::record("type=$type cid=$cid, time_type=$time_type has been stat.",Log::DEBUG); continue; } if($parent_id > 0 && $confirmed == false) { Log::record("type=$type cid=$cid, time_type=$time_type had not confirmed.",Log::DEBUG); continue; } $ret = $this->add_balance($type, $cid, $start, $end, $time_type, $parent_id); if(!$ret) { Log::record("type=$type cid=$cid, time_type=$time_type fail",Log::ERR); } } } } } private function find_parent($type, $cid, $time_type) { $mod = Model('refill_balance'); $cond = ['type' => $type, 'cid' => $cid, 'time_type' => $time_type]; $item = $mod->field('balance_id,end_stamp,confirmed')->where($cond)->order('end_stamp desc')->find(); $confirmed = boolval($item['confirmed']); return [intval($item['balance_id']), intval($item['end_stamp']), $confirmed]; } private function refill_time_finder($type, $cid, $start,$end) { if ($start != 0) { return $start; } if ($type == 'system') { $mod_refill = Model('refill_order'); $item = $mod_refill->table('refill_order')->field('order_id,order_time') ->where(['order_time' => ['lt', $end]]) ->order('order_id asc')->find(); $time = $item['order_time'] ?? $end; } elseif ($type == 'merchant') { $mod_refill = Model('refill_order'); $item = $mod_refill->table('refill_order')->field('order_id,order_time') ->where(['mchid' => $cid, 'order_time' => ['lt', $end]]) ->order('order_id asc')->find(); $time = $item['order_time'] ?? $end; } else { $mod_refill = Model('vr_order'); $item = $mod_refill->table('vr_order')->field('order_id,add_time') ->where(['store_id' => $cid,'add_time' => ['lt', $end]]) ->order('order_id asc')->find(); $time = $item['add_time'] ?? $end; } return $time; } private function merchant_paytime_finder($cid, $start, $end) { if ($start != 0) { return $start; } $mod_pay = Model(); if ($cid == 0) { $item = $mod_pay->table('refill_evidence') ->field('min(add_time) as madd_time') ->where(['add_time' => ['lt', $end]]) ->find(); } else { $item = $mod_pay->table('refill_evidence') ->field('min(add_time) as madd_time') ->where(['mchid' => $cid,'add_time' => ['lt', $end]]) ->find(); } $time = $item['madd_time'] ?? $end; return $time; } private function provider_paytime_finder($cid, $start,$end) { if ($start != 0) { return $start; } $mod_pay = Model(); if ($cid == 0) { $item = $mod_pay->table('provider_amount') ->field('min(add_time) as madd_time') ->where(['add_time' => ['lt', $end]]) ->find(); } else { $item = $mod_pay->table('provider_amount') ->field('min(add_time) as madd_time') ->where(['provider_id' => $cid,'add_time' => ['lt', $end]]) ->find(); } $time = $item['madd_time'] ?? $end; return $time; } private function balance_data($type, $cid, $start, $end, $time_type, $parent_balance, $remark) { $refill_time = $this->refill_time_finder($type, $cid, $start,$end); $order_stat = $this->order_stat($type, $cid, $refill_time, $end, $time_type); $transfer_calcer = function ($detail,$types = []) { $result = 0.0; foreach ($detail as $type => $amount) { if(empty($types)) { $result += $amount; } elseif(in_array($type,$types)) { $result += $amount; } } return $result; }; if ($type == 'system') { $merchant_time = $this->merchant_paytime_finder($cid, $start,$end); $transfer_detail = $this->merchant_evidence_stat($cid, $merchant_time, $end); $provider_time = $this->provider_paytime_finder($cid, $start,$end); $out = $this->provider_amount_stat(0, $provider_time, $end); $cname = 'system'; $pay_time = min($merchant_time,$provider_time); $in = $transfer_calcer($transfer_detail); $balance = ncPriceFormat($in - $out); } elseif ($type == 'merchant') { $pay_time = $this->merchant_paytime_finder($cid, $start, $end); $transfer_detail = $this->merchant_evidence_stat($cid, $pay_time, $end); $out = "0.0000"; $cname = $this->mMerchantNames[$cid]; $in = $transfer_calcer($transfer_detail); $balance = ncPriceFormat($in - $order_stat['mch_amounts']); } else { $pid = $this->mStoreidPID[$cid]; $pay_time = $this->provider_paytime_finder($pid, $start,$end); $out = $this->provider_amount_stat($pid, $pay_time, $end); $cname = $this->mProviderNames[$cid]; $balance = ncPriceFormat($out - $order_stat['channel_amounts']); } if ($start == 0) { $time = min($refill_time, $pay_time); $start = strtotime(date('Y-m-d', $time)); } $accumuter = function ($parent_id) { if ($parent_id > 0) { $item = Model('refill_balance')->getBalance(['balance_id' => $parent_id]); } else { $item = []; } if (empty($item)) { return 0.00; } else { return $item['accumulate_balance'] + $item['balance']; } }; $transfer_in = $transfer_calcer($transfer_detail,[merchantModel::type_mch_deposit,merchantModel::type_adm_deposit]); $except_amount = $transfer_calcer($transfer_detail,[merchantModel::type_adm_adjust,merchantModel::type_adm_finpos]); $refund_amount = $transfer_calcer($transfer_detail,[merchantModel::type_refund_back]); return ['parent_id' => $parent_balance, 'type' => $type, 'cid' => $cid, 'cname' => $cname, 'start_stamp' => $start, 'end_stamp' => $end, 'end_text' => date('Y-m-d H:i:s', $end), 'success_count' => intval($order_stat['order_counts']), 'refill_amount' => ncPriceFormat($order_stat['refill_amounts']), 'mch_amount' => ncPriceFormat($order_stat['mch_amounts']), 'channel_amount' => ncPriceFormat($order_stat['channel_amounts']), 'service_amount' => ncPriceFormat(0), 'profit_amount' => ncPriceFormat($order_stat['profit_amounts']), 'transfer_detail' => json_encode($transfer_detail), 'transfer_in' => ncPriceFormat($transfer_in), 'except_amount' => ncPriceFormat($except_amount), 'refund_amount' => ncPriceFormat($refund_amount), 'transfer_out' => ncPriceFormat($out), 'accumulate_balance' => ncPriceFormat($accumuter($parent_balance)), 'balance' => ncPriceFormat($balance), 'update_time' => time(), 'confirmed' => 0, 'time_type' => $time_type, 'remark' => $remark, ]; } //system,provider,merchant //cid=0,mchid,store_id public function add_balance($type, $cid, $start, $end, $time_type, $parent_balance = 0, $remark = '系统自动生成') { $data = $this->balance_data($type, $cid, $start, $end, $time_type, $parent_balance, $remark); if(empty($data)) { return false; } $ret = Model('refill_balance')->insert($data); return $ret != false; } public function rebuild_balance($balance_id) { $balance = Model('refill_balance')->getBalance(['balance_id' => $balance_id]); if(empty($balance)) return false; $type = $balance['type']; $cid = $balance['cid']; $start = $balance['start_stamp']; $end = $balance['end_stamp']; $time_type = $balance['time_type']; $parent_balance = $balance['parent_id']; $remark = '记录重新生成'; $data = $this->balance_data($type, $cid, $start, $end, $time_type, $parent_balance, $remark); if(empty($data)) { return false; } $ret = Model('refill_balance')->where(['balance_id' => $balance_id])->update($data); return $ret != false; } private function order_stat($type, $cid, $start, $end, $time_type) { $cond = [ 'refill_order.inner_status' => 0, 'vr_order.order_state' => 40 ]; if($type == 'provider') { $cond['vr_order.store_id'] = $cid; } elseif($type == 'merchant') { $cond['refill_order.mchid'] = $cid; } if($time_type == 'notify_time') { $order_start = $start - 3 * self::DaySecs; if($order_start < 0) { $order_start = 0; } $cond["refill_order.notify_time&refill_order.notify_time"] = ['_multi' => true, ['egt', $start], ['lt', $end]]; $cond["refill_order.order_time&refill_order.order_time"] = ['_multi' => true, ['egt', $order_start], ['lt', $end]]; $cond["vr_order.add_time&vr_order.add_time"] = ['_multi' => true, ['egt', $order_start], ['lt', $end]]; } else { $add_end = $end + 3 * self::DaySecs; $cond["refill_order.order_time&refill_order.order_time"] = ['_multi' => true, ['egt', $start], ['lt', $end]]; $cond["vr_order.add_time&vr_order.add_time"] = ['_multi' => true, ['egt', $start], ['lt', $add_end]]; } $record = Model('')->table('refill_order,vr_order') ->field('count(*) as order_counts, sum(refill_amount) as refill_amounts, sum(mch_amount) as mch_amounts, sum(channel_amount) as channel_amounts') ->join('inner') ->on('refill_order.order_id=vr_order.order_id') ->where($cond) ->find(); if(!empty($record)) { $record['profit_amounts'] = ncPriceFormat($record['mch_amounts'] - $record['channel_amounts']); } return $record; } private function merchant_evidence_stat($cid, $start, $end) { $cond['status'] = merchantModel::status_passed; $cond['is_operation'] = merchantModel::oper_deposited; if($cid > 0) { $cond['mchid'] = $cid; } $cond['check_time&check_time'] = ['_multi' => true, ['egt', $start], ['lt', $end]]; $items = Model('')->table('refill_evidence') ->field('add_type,sum(amount) as amounts') ->where($cond) ->group('add_type') ->select(); $records = []; foreach ($items as $item) { $add_type = intval($item['add_type']); $amounts = floatval(ncPriceFormat($item['amounts'])); $records[$add_type] = $amounts; } return $records; } private function provider_amount_stat($provider_id, $start, $end) { if($provider_id > 0) { $cond['provider_id'] = $provider_id; } $cond['add_time&add_time'] = ['_multi' => true, ['egt', $start], ['lt', $end]]; $record = Model('')->table('provider_amount') ->field('sum(amount) as amounts') ->where($cond) ->find(); return ncPriceFormat($record['amounts']); } }