OwnerFeeTotalService.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  1. <?php
  2. namespace App\Services;
  3. use App\OrderIssue;
  4. use App\Owner;
  5. use App\OwnerBillReport;
  6. use App\OwnerFeeOperation;
  7. use App\OwnerPriceOperation;
  8. use App\OwnerPriceOperationItem;
  9. use App\OwnerStoreOutFeeReport;
  10. use App\Traits\ServiceAppAop;
  11. use App\OwnerFeeTotal;
  12. use App\Traits\SettlementBillServiceTrait;
  13. use Illuminate\Database\Eloquent\Builder;
  14. class OwnerFeeTotalService
  15. {
  16. const TYPE = '总费用';
  17. use ServiceAppAop;
  18. use SettlementBillServiceTrait;
  19. protected $modelClass = OwnerFeeTotal::class;
  20. /**
  21. * 生成统计数据
  22. * @param string|null $counting_month string 统计月份默认为上一个月
  23. */
  24. public function record(string $counting_month = null)
  25. {
  26. if (is_null($counting_month)) {
  27. $counting_month = now()->subMonth()->startOfMonth()->toDateString();
  28. }
  29. /**
  30. * 仓储。入库,出库
  31. * 1. 查到所有货主
  32. * 2. 遍历货主
  33. * 3. 获得货主下的计费模型,将计费模型里面的数据转换成“描述”
  34. * 4. 查询相关表,获得指定计费模型下的费用总和(含税费)
  35. *
  36. * 配送,加工,系统使用,杂项
  37. * 1. 查询对应表的总和即可,不需关联计费模型
  38. *
  39. * 理赔
  40. * 1. 暂不明确
  41. *
  42. * 优惠
  43. * 1. 一个字段,在结算管理-账单却认下添加一个优惠输入的字段
  44. *
  45. * 税率
  46. * 1. 计算得出:总税费/总金额
  47. */
  48. //仓储:ownerStoragePriceModels。入库,出库:ownerPriceOperations
  49. $owners = Owner::query()
  50. ->with([
  51. "ownerStoragePriceModels.unit:id,name",
  52. "ownerStoragePriceModels.timeUnit:id,name",
  53. "ownerPriceOperations" => function ($query) {
  54. /** @var Builder $query */
  55. $query->with(["items" => function ($query) {
  56. /** @var Builder $query */
  57. $query->with(['unit'])->orderByRaw("CASE strategy WHEN '起步' THEN 1 WHEN '默认' THEN 2 WHEN '特征' THEN 3 END");
  58. }]);
  59. }])
  60. ->where('deleted_at', '>=', now()->subMonth()->startOfMonth())
  61. ->orWhereNull('deleted_at')->get();
  62. foreach ($owners as $owner) {
  63. $information = $this->buildInformation($owner, $counting_month);
  64. $ownerFeeTotal = [];
  65. $ownerFeeTotal['information'] = $information;
  66. //快递费
  67. $ownerFeeTotal = $this->buildExpressFee($owner, $counting_month, $ownerFeeTotal);
  68. //物流费
  69. $ownerFeeTotal = $this->buildLogisticFee($owner, $counting_month, $ownerFeeTotal);
  70. //加工
  71. $ownerFeeTotal = $this->buildProcessFee($owner, $counting_month, $ownerFeeTotal);
  72. //系统使用费
  73. $ownerFeeTotal = $this->buildSystemFee($counting_month, $owner, $ownerFeeTotal);
  74. //杂项费
  75. $ownerFeeTotal = $this->buildSundryFee($owner, $counting_month, $ownerFeeTotal);
  76. //理赔
  77. $ownerFeeTotal = $this->buildIndemnityFee($counting_month, $owner, $ownerFeeTotal);
  78. // 包材费
  79. $ownerFeeTotal = $this->buildPackingMaterialFee($owner, $counting_month, $ownerFeeTotal);
  80. // 卸货费
  81. $ownerFeeTotal = $this->buildUnloadFee($owner, $counting_month, $ownerFeeTotal);
  82. //总费用 和 总税费
  83. list($totalFee, $totalTaxFee, $ownerFeeTotal) = $this->calTotalFeeAndTotalTaxFee($ownerFeeTotal);
  84. //税率
  85. $ownerFeeTotal = $this->calTaxRate($totalTaxFee, $totalFee, $ownerFeeTotal);
  86. $insertData = $this->buildInsertData($owner, $counting_month, $ownerFeeTotal);
  87. $this->createOrUpdate($owner, $counting_month, $insertData);
  88. }
  89. }
  90. public function get(array $kvPairs)
  91. {
  92. return OwnerFeeTotal::query()
  93. ->where('owner_id', $kvPairs['owner_id'])
  94. ->where('counting_month', $kvPairs['counting_month'])
  95. ->firstOr(function (){
  96. return new OwnerFeeTotal();
  97. });
  98. }
  99. /**
  100. * 出库入库描述
  101. * @param $ownerPriceOperation
  102. * @return array
  103. */
  104. private function buildPriceRemarks($ownerPriceOperation): array
  105. {
  106. //起步: 3 件 / 2.7000元 (满减单价: 0-19999 单(2.7元) , 20000-49999 单(2.5元) , 50000-99999 单(2元) , 100000+ 单(1.6元) )
  107. //默认续费: 1 件 / 0.5000元 (满减单价: 0-19999 单(0.5元) , 20000-49999 单(0.4元) , 50000-99999 单(0.3元) , 100000+ 单(0.2元) )
  108. $discount_counts = explode(',', $ownerPriceOperation->discount_count);
  109. $priceRemarks = [];
  110. foreach ($ownerPriceOperation->items as $operationItem) {
  111. $discount_prices = explode(',', $operationItem->discount_price);
  112. $strategy = $operationItem->strategy == '起步' ? '起步' : '默认续费';
  113. $unit_name = $operationItem->unit->name ?? '个';
  114. $priceRemark = "{$strategy}: {$operationItem->amount} {$unit_name}/{$operationItem->unit_price}元";
  115. if (!empty($discount_prices)) {
  116. $priceRemark .= "(满减单价:";
  117. for ($i = 0; $i < count($discount_counts) - 1; $i++) {
  118. $next_discount_count = $discount_counts[$i + 1] ?? '+';
  119. $discount_count = $discount_counts[$i] ?? '';
  120. $discount_price = $discount_prices[$i] ?? '';
  121. $priceRemark .= "{$discount_count}-{$next_discount_count} {$unit_name} {$discount_price}元,";
  122. }
  123. $priceRemark .= ")";
  124. }
  125. $priceRemarks[] = $priceRemark;
  126. }
  127. return $priceRemarks;
  128. }
  129. /**
  130. * @param $owner
  131. * @param $counting_month
  132. * @return array|array[]
  133. */
  134. private function buildInformation($owner, $counting_month): array
  135. {
  136. //获取特征信息
  137. $features = app("FeatureService")->getMapArray();
  138. OwnerPriceOperation::$features = $features;
  139. OwnerPriceOperationItem::$features = $features;
  140. foreach ($owner->ownerPriceOperations as &$operation) {
  141. $operation["featureFormat"] = $operation->featureFormat;
  142. $operation["isRejected"] = $operation->type_mark === 0;
  143. foreach ($operation->items as &$item) {
  144. $item["featureFormat"] = $item->featureFormat;
  145. if ($item["strategy"] == "起步") $item["type"] = $item["amount"] ? 0 : 1;
  146. }
  147. }
  148. $information = [
  149. //仓储
  150. 'storageFee' => [],
  151. //入库
  152. 'storeFee' => [],
  153. //出库
  154. 'storeOutFee' => [],
  155. ];
  156. //仓储
  157. foreach ($owner->ownerStoragePriceModels as $ownerStoragePriceModel) {
  158. /**@var $areaFeeService SettlementBillsAreaFeeService */
  159. $areaFeeService = app('SettlementBillsAreaFeeService');
  160. $remark = "起租面积:{$ownerStoragePriceModel->minimum_area},{$ownerStoragePriceModel->price[0]}元/{$ownerStoragePriceModel->unit->name}/{$ownerStoragePriceModel->timeUnit->name}";
  161. $information['storageFee'][] = [
  162. 'name' => $ownerStoragePriceModel->name,
  163. 'remark' => $remark,
  164. 'id' => $ownerStoragePriceModel->id,
  165. 'fee' => $areaFeeService->getTotalFee($owner->id, $counting_month)->storage_fee ?? 0,
  166. 'tax_fee' => $areaFeeService->getTotalFee($owner->id, $counting_month)->storage_tax_fee ?? 0
  167. ];
  168. }
  169. $ownerPriceOperationsGrouped = $owner->ownerPriceOperations->groupBy('operation_type');
  170. //入库
  171. $ownerStoreFeeReports = \App\OwnerStoreFeeReport::query()
  172. ->selectRaw("
  173. sum(fee) as fee,
  174. sum(tax_fee) as tax_fee,
  175. model_id
  176. ")
  177. ->where('counting_month', $counting_month)
  178. ->where('owner_id', $owner->id)
  179. ->groupBy('model_id')
  180. ->get();
  181. $ownerStoreFeeReportsGroupByModelId = $ownerStoreFeeReports->groupBy('model_id')->toArray();
  182. foreach ($ownerPriceOperationsGrouped['入库'] ?? [] as $ownerPriceOperationsGroupedItem) {
  183. try {
  184. $fee = $ownerStoreFeeReportsGroupByModelId[$ownerPriceOperationsGroupedItem->id][0]['fee'];
  185. } catch (\Exception $e) {
  186. $fee = $ownerStoreFeeReportsGroupByModelId[$ownerPriceOperationsGroupedItem->target_id][0]['fee'] ?? 0;
  187. $ownerPriceOperationsGroupedItem = OwnerPriceOperation::query()->with(['items'])->find($ownerPriceOperationsGroupedItem->target_id);
  188. }
  189. if ($fee > 0) {
  190. $information['storeFee'][] = [
  191. 'name' => $ownerPriceOperationsGroupedItem->name,
  192. 'remark' => $this->buildPriceRemarks($ownerPriceOperationsGroupedItem),
  193. 'id' => $ownerPriceOperationsGroupedItem->id,
  194. 'fee' => $fee,
  195. 'tax_fee' => $ownerStoreFeeReportsGroupByModelId[$ownerPriceOperationsGroupedItem->id][0]['tax_fee'] ?? 0,
  196. ];
  197. }
  198. }
  199. //出库
  200. $ownerStoreOutFeeReports = OwnerStoreOutFeeReport::query()
  201. ->selectRaw("
  202. sum(fee) as fee,
  203. sum(tax_fee) as tax_fee,
  204. model_id
  205. ")
  206. ->where('counting_month', $counting_month)
  207. ->where('owner_id', $owner->id)
  208. ->groupBy('model_id')
  209. ->get();
  210. $ownerStoreOutFeeReportsGroupByModelId = $ownerStoreOutFeeReports->groupBy('model_id')->toArray();
  211. foreach ($ownerPriceOperationsGrouped['出库'] ?? [] as $ownerPriceOperationsGroupedItem) {
  212. try {
  213. $fee = $ownerStoreOutFeeReportsGroupByModelId[$ownerPriceOperationsGroupedItem->id][0]['fee'];
  214. } catch (\Exception $e) {
  215. $fee = $ownerStoreOutFeeReportsGroupByModelId[$ownerPriceOperationsGroupedItem->target_id][0]['fee'] ?? 0;
  216. $ownerPriceOperationsGroupedItem = OwnerPriceOperation::query()->with(['items'])->find($ownerPriceOperationsGroupedItem->target_id);
  217. }
  218. if ($fee > 0) {
  219. $information['storeOutFee'][] = [
  220. 'name' => $ownerPriceOperationsGroupedItem->name,
  221. 'remark' => $this->buildPriceRemarks($ownerPriceOperationsGroupedItem),
  222. 'id' => $ownerPriceOperationsGroupedItem->id,
  223. 'fee' => $fee,
  224. 'tax_fee' => $ownerStoreOutFeeReportsGroupByModelId[$ownerPriceOperationsGroupedItem->id][0]['tax_fee'] ?? 0,
  225. ];
  226. }
  227. }
  228. return $information;
  229. }
  230. /**
  231. * @param $owner
  232. * @param string|null $counting_month
  233. * @param array $ownerFeeTotal
  234. * @return array
  235. */
  236. private function buildExpressFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  237. {
  238. /**@var $expressFeeService OwnerLogisticFeeReportService */
  239. $expressFeeService = app('OwnerLogisticFeeReportService');
  240. $expressFeeTotal = $expressFeeService->getTotalFee($owner->id, $counting_month);
  241. $ownerFeeTotal ['expressFee'] = [
  242. 'fee' => $expressFeeTotal->fee ?? 0,
  243. 'tax_fee' => $expressFeeTotal->tax_fee ?? 0,
  244. ];
  245. return $ownerFeeTotal;
  246. }
  247. /**
  248. * @param $owner
  249. * @param string|null $counting_month
  250. * @param array $ownerFeeTotal
  251. * @return array
  252. */
  253. private function buildLogisticFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  254. {
  255. /**@var $waybillSettlementBillService OwnerWaybillSettlementBillService */
  256. $waybillSettlementBillService = app('OwnerWaybillSettlementBillService');
  257. $logisticFeeTotal = $waybillSettlementBillService->getTotalFee($owner->id, $counting_month);
  258. $ownerFeeTotal ['logisticFee'] = [
  259. 'fee' => $logisticFeeTotal->fee ?? 0,
  260. 'tax_fee' => $logisticFeeTotal->tax_fee ?? 0,
  261. ];
  262. return $ownerFeeTotal;
  263. }
  264. /**
  265. * @param $owner
  266. * @param string|null $counting_month
  267. * @param array $ownerFeeTotal
  268. * @return array
  269. */
  270. private function buildProcessFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  271. {
  272. /**@var $ownerProcessSettlementBillService OwnerProcessSettlementBillService */
  273. $ownerProcessSettlementBillService = app('OwnerProcessSettlementBillService');
  274. $processFeeTotal = $ownerProcessSettlementBillService->getTotalFee($owner->id, $counting_month);
  275. $ownerFeeTotal ['processFee'] = [
  276. 'fee' => $processFeeTotal->fee ?? 0,
  277. 'tax_fee' => $processFeeTotal->tax_fee ?? 0,
  278. ];
  279. return $ownerFeeTotal;
  280. }
  281. /**
  282. * @param string|null $counting_month
  283. * @param $owner
  284. * @param array $ownerFeeTotal
  285. * @return array
  286. */
  287. private function buildSystemFee(?string $counting_month, $owner, array $ownerFeeTotal): array
  288. {
  289. $ownerBillReport = OwnerBillReport::query()
  290. ->where('counting_month', $counting_month)
  291. ->where('owner_id', $owner->id)
  292. ->first();
  293. $ownerFeeTotal ['systemFee'] = [
  294. 'fee' => $ownerBillReport->other_fee ?? 0,
  295. 'tax_fee' => $ownerBillReport->other_tax_fee ?? 0,
  296. ];
  297. return $ownerFeeTotal;
  298. }
  299. /**
  300. * @param $owner
  301. * @param string|null $counting_month
  302. * @param array $ownerFeeTotal
  303. * @return array
  304. */
  305. private function buildSundryFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  306. {
  307. /**@var $ownerSundryFeeDetailService OwnerSundryFeeDetailService */
  308. $ownerSundryFeeDetailService = app('OwnerSundryFeeDetailService');
  309. $sundryFeeTotals = $ownerSundryFeeDetailService->getTotalFee($owner->id, $counting_month);
  310. if (!$sundryFeeTotals->isEmpty()) {
  311. foreach ($sundryFeeTotals as $sundryFeeTotal) {
  312. $ownerFeeTotal ['sundryFee'][] = [
  313. 'type' => $sundryFeeTotal->type,
  314. 'fee' => $sundryFeeTotal->fee,
  315. ];
  316. }
  317. } else {
  318. $ownerFeeTotal ['sundryFee'] = [];
  319. }
  320. return $ownerFeeTotal;
  321. }
  322. /**
  323. * @param string|null $counting_month
  324. * @param $owner
  325. * @param array $ownerFeeTotal
  326. * @return array
  327. */
  328. private function buildIndemnityFee(?string $counting_month, $owner, array $ownerFeeTotal): array
  329. {
  330. list($start, $end) = $this->getStartAndEnd($counting_month);
  331. $indemnityFee = OrderIssue::query()
  332. ->selectRaw("sum(baoshi_indemnity_money) as fee,owner_id,order_id")
  333. ->leftJoin('orders', 'order_issues.order_id', '=', 'orders.id')
  334. ->where('owner_id', $owner->id)
  335. ->whereBetween('order_issues.created_at', [$start, $end])->first();
  336. $ownerFeeTotal ['indemnityFee'] = [
  337. 'fee' => $indemnityFee->fee ?? 0,
  338. ];
  339. return $ownerFeeTotal;
  340. }
  341. /**
  342. * @param $owner
  343. * @param string|null $counting_month
  344. * @param array $ownerFeeTotal
  345. * @return array
  346. */
  347. private function buildPackingMaterialFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  348. {
  349. /**@var $packingMaterialFeeService OwnerProcurementSettlementBillService */
  350. $packingMaterialFeeService = app('OwnerProcurementSettlementBillService');
  351. $packingMaterialFee = $packingMaterialFeeService->getTotalFee($owner->id, $counting_month);
  352. $ownerFeeTotal ['packingMaterialFee'] = [
  353. 'fee' => $packingMaterialFee ?? 0,
  354. ];
  355. return $ownerFeeTotal;
  356. }
  357. /**
  358. * @param $owner
  359. * @param string|null $counting_month
  360. * @param array $ownerFeeTotal
  361. * @return array
  362. */
  363. private function buildUnloadFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  364. {
  365. /**@var $unloadService OwnerDischargeTaskSettlementBillService */
  366. $unloadService = app('OwnerDischargeTaskSettlementBillService');
  367. $unloadFee = $unloadService->getTotalFee($owner->id, $counting_month);
  368. $ownerFeeTotal ['unloadFee'] = [
  369. 'fee' => $unloadFee ?? 0,
  370. ];
  371. return $ownerFeeTotal;
  372. }
  373. /**
  374. * @param array $ownerFeeTotal
  375. * @return array
  376. */
  377. private function calTotalFeeAndTotalTaxFee(array $ownerFeeTotal): array
  378. {
  379. $totalFee = 0;
  380. $totalTaxFee = 0;
  381. foreach ($ownerFeeTotal as $key => $ownerFeeTotalItem) {
  382. if ($key == 'information') {
  383. list($totalFee, $totalTaxFee) = $this->calInformationTotalFeeAndTotalTaxFee($ownerFeeTotalItem, $totalFee, $totalTaxFee);
  384. } else if ($key == 'sundryFee') {
  385. foreach ($ownerFeeTotalItem as $sundryFeeItem) {
  386. $totalFee += $sundryFeeItem['fee'] ?? 0;
  387. }
  388. } else {
  389. $totalFee += $ownerFeeTotalItem['fee'] ?? 0;
  390. $totalTaxFee += $ownerFeeTotalItem['tax_fee'] ?? 0;
  391. }
  392. }
  393. $ownerFeeTotal['totalFee'] = $totalFee;
  394. $ownerFeeTotal['totalTaxFee'] = $totalTaxFee;
  395. return array($totalFee, $totalTaxFee, $ownerFeeTotal);
  396. }
  397. /**
  398. * @param $totalTaxFee
  399. * @param $totalFee
  400. * @param $ownerFeeTotal
  401. * @return mixed
  402. */
  403. private function calTaxRate($totalTaxFee, $totalFee, $ownerFeeTotal)
  404. {
  405. try {
  406. $taxRate = ($totalTaxFee / $totalFee) * 100 ?? 0;
  407. } catch (\Exception $e) {
  408. $taxRate = 0;
  409. }
  410. $ownerFeeTotal['taxRate'] = $taxRate;
  411. return $ownerFeeTotal;
  412. }
  413. /**
  414. * @param $owner
  415. * @param string|null $counting_month
  416. * @param $ownerFeeTotal
  417. * @return array
  418. */
  419. private function buildInsertData($owner, ?string $counting_month, $ownerFeeTotal): array
  420. {
  421. return [
  422. 'owner_id' => $owner->id,
  423. 'counting_month' => $counting_month,
  424. 'information' => $ownerFeeTotal['information'],
  425. 'fee' => $ownerFeeTotal['totalFee'],
  426. 'logistic_fee' => $ownerFeeTotal['logisticFee']['fee'],
  427. 'logistic_tax_fee' => $ownerFeeTotal['logisticFee']['tax_fee'],
  428. 'express_fee' => $ownerFeeTotal['expressFee']['fee'],
  429. 'express_tax_fee' => $ownerFeeTotal['expressFee']['tax_fee'],
  430. 'process_fee' => $ownerFeeTotal['processFee']['fee'],
  431. 'process_tax_fee' => $ownerFeeTotal['processFee']['tax_fee'],
  432. 'system_fee' => $ownerFeeTotal['systemFee']['fee'],
  433. 'system_tax_fee' => $ownerFeeTotal['systemFee']['tax_fee'],
  434. 'sundry_information' => $ownerFeeTotal['sundryFee'],
  435. 'packing_material_fee' => $ownerFeeTotal['packingMaterialFee']['fee'],
  436. 'unload_fee' => $ownerFeeTotal['unloadFee']['fee'],
  437. 'tax_rate' => $ownerFeeTotal['taxRate'],
  438. 'indemnity_fee' => $ownerFeeTotal['indemnityFee']['fee'],
  439. ];
  440. }
  441. /**
  442. * @param $ownerFeeTotalItem
  443. * @param $totalFee
  444. * @param $totalTaxFee
  445. * @return array|int[]
  446. */
  447. private function calInformationTotalFeeAndTotalTaxFee($ownerFeeTotalItem, $totalFee, $totalTaxFee): array
  448. {
  449. foreach ($ownerFeeTotalItem as $ownerFeeTotalItemOne) {
  450. foreach ($ownerFeeTotalItemOne as $feeItem) {
  451. $totalFee += $feeItem['fee'] ?? 0;
  452. $totalTaxFee += $feeItem['tax_fee'] ?? 0;
  453. }
  454. }
  455. return array($totalFee, $totalTaxFee);
  456. }
  457. /**
  458. * @param $owner
  459. * @param string|null $counting_month
  460. * @param array $insertData
  461. */
  462. private function createOrUpdate($owner, ?string $counting_month, array $insertData): void
  463. {
  464. if (OwnerFeeTotal::query()->where('owner_id', $owner->id)->where('counting_month', $counting_month)->exists()) {
  465. OwnerFeeTotal::query()
  466. ->where('owner_id', $owner->id)
  467. ->where('counting_month', $counting_month)
  468. ->update($insertData);
  469. } else {
  470. OwnerFeeTotal::query()
  471. ->where('owner_id', $owner->id)
  472. ->where('counting_month', $counting_month)
  473. ->create($insertData);
  474. }
  475. }
  476. }