OwnerFeeTotalService.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  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. ->first();
  96. }
  97. /**
  98. * 出库入库描述
  99. * @param $ownerPriceOperation
  100. * @return array
  101. */
  102. private function buildPriceRemarks($ownerPriceOperation): array
  103. {
  104. //起步: 3 件 / 2.7000元 (满减单价: 0-19999 单(2.7元) , 20000-49999 单(2.5元) , 50000-99999 单(2元) , 100000+ 单(1.6元) )
  105. //默认续费: 1 件 / 0.5000元 (满减单价: 0-19999 单(0.5元) , 20000-49999 单(0.4元) , 50000-99999 单(0.3元) , 100000+ 单(0.2元) )
  106. $discount_counts = explode(',', $ownerPriceOperation->discount_count);
  107. $priceRemarks = [];
  108. foreach ($ownerPriceOperation->items as $operationItem) {
  109. $discount_prices = explode(',', $operationItem->discount_price);
  110. $strategy = $operationItem->strategy == '起步' ? '起步' : '默认续费';
  111. $unit_name = $operationItem->unit->name ?? '个';
  112. $priceRemark = "{$strategy}: {$operationItem->amount} {$unit_name}/{$operationItem->unit_price}元";
  113. if (!empty($discount_prices)) {
  114. $priceRemark .= "(满减单价:";
  115. for ($i = 0; $i < count($discount_counts) - 1; $i++) {
  116. $next_discount_count = $discount_counts[$i + 1] ?? '+';
  117. $discount_count = $discount_counts[$i] ?? '';
  118. $discount_price = $discount_prices[$i] ?? '';
  119. $priceRemark .= "{$discount_count}-{$next_discount_count} {$unit_name} {$discount_price}元,";
  120. }
  121. $priceRemark .= ")";
  122. }
  123. $priceRemarks[] = $priceRemark;
  124. }
  125. return $priceRemarks;
  126. }
  127. /**
  128. * @param $owner
  129. * @param $counting_month
  130. * @return array|array[]
  131. */
  132. private function buildInformation($owner, $counting_month): array
  133. {
  134. //获取特征信息
  135. $features = app("FeatureService")->getMapArray();
  136. OwnerPriceOperation::$features = $features;
  137. OwnerPriceOperationItem::$features = $features;
  138. foreach ($owner->ownerPriceOperations as &$operation) {
  139. $operation["featureFormat"] = $operation->featureFormat;
  140. $operation["isRejected"] = $operation->type_mark === 0;
  141. foreach ($operation->items as &$item) {
  142. $item["featureFormat"] = $item->featureFormat;
  143. if ($item["strategy"] == "起步") $item["type"] = $item["amount"] ? 0 : 1;
  144. }
  145. }
  146. $information = [
  147. //仓储
  148. 'storageFee' => [],
  149. //入库
  150. 'storeFee' => [],
  151. //出库
  152. 'storeOutFee' => [],
  153. ];
  154. //仓储
  155. foreach ($owner->ownerStoragePriceModels as $ownerStoragePriceModel) {
  156. /**@var $areaFeeService SettlementBillsAreaFeeService */
  157. $areaFeeService = app('SettlementBillsAreaFeeService');
  158. $remark = "起租面积:{$ownerStoragePriceModel->minimum_area},{$ownerStoragePriceModel->price[0]}元/{$ownerStoragePriceModel->unit->name}/{$ownerStoragePriceModel->timeUnit->name}";
  159. $information['storageFee'][] = [
  160. 'name' => $ownerStoragePriceModel->name,
  161. 'remark' => $remark,
  162. 'id' => $ownerStoragePriceModel->id,
  163. 'fee' => $areaFeeService->getTotalFee($owner->id, $counting_month)->storage_fee ?? 0,
  164. 'tax_fee' => $areaFeeService->getTotalFee($owner->id, $counting_month)->storage_tax_fee ?? 0
  165. ];
  166. }
  167. $ownerPriceOperationsGrouped = $owner->ownerPriceOperations->groupBy('operation_type');
  168. //入库
  169. $ownerStoreFeeReports = \App\OwnerStoreFeeReport::query()
  170. ->selectRaw("
  171. sum(fee) as fee,
  172. sum(tax_fee) as tax_fee,
  173. model_id
  174. ")
  175. ->where('counting_month', $counting_month)
  176. ->where('owner_id', $owner->id)
  177. ->groupBy('model_id')
  178. ->get();
  179. $ownerStoreFeeReportsGroupByModelId = $ownerStoreFeeReports->groupBy('model_id')->toArray();
  180. foreach ($ownerPriceOperationsGrouped['入库'] ?? [] as $ownerPriceOperationsGroupedItem) {
  181. try {
  182. $fee = $ownerStoreFeeReportsGroupByModelId[$ownerPriceOperationsGroupedItem->id][0]['fee'];
  183. } catch (\Exception $e) {
  184. $fee = $ownerStoreFeeReportsGroupByModelId[$ownerPriceOperationsGroupedItem->target_id][0]['fee'] ?? 0;
  185. $ownerPriceOperationsGroupedItem = OwnerPriceOperation::query()->with(['items'])->find($ownerPriceOperationsGroupedItem->target_id);
  186. }
  187. if ($fee > 0) {
  188. $information['storeFee'][] = [
  189. 'name' => $ownerPriceOperationsGroupedItem->name,
  190. 'remark' => $this->buildPriceRemarks($ownerPriceOperationsGroupedItem),
  191. 'id' => $ownerPriceOperationsGroupedItem->id,
  192. 'fee' => $fee,
  193. 'tax_fee' => $ownerStoreFeeReportsGroupByModelId[$ownerPriceOperationsGroupedItem->id][0]['tax_fee'] ?? 0,
  194. ];
  195. }
  196. }
  197. //出库
  198. $ownerStoreOutFeeReports = OwnerStoreOutFeeReport::query()
  199. ->selectRaw("
  200. sum(fee) as fee,
  201. sum(tax_fee) as tax_fee,
  202. model_id
  203. ")
  204. ->where('counting_month', $counting_month)
  205. ->where('owner_id', $owner->id)
  206. ->groupBy('model_id')
  207. ->get();
  208. $ownerStoreOutFeeReportsGroupByModelId = $ownerStoreOutFeeReports->groupBy('model_id')->toArray();
  209. foreach ($ownerPriceOperationsGrouped['出库'] ?? [] as $ownerPriceOperationsGroupedItem) {
  210. try {
  211. $fee = $ownerStoreOutFeeReportsGroupByModelId[$ownerPriceOperationsGroupedItem->id][0]['fee'];
  212. } catch (\Exception $e) {
  213. $fee = $ownerStoreOutFeeReportsGroupByModelId[$ownerPriceOperationsGroupedItem->target_id][0]['fee'] ?? 0;
  214. $ownerPriceOperationsGroupedItem = OwnerPriceOperation::query()->with(['items'])->find($ownerPriceOperationsGroupedItem->target_id);
  215. }
  216. if ($fee > 0) {
  217. $information['storeOutFee'][] = [
  218. 'name' => $ownerPriceOperationsGroupedItem->name,
  219. 'remark' => $this->buildPriceRemarks($ownerPriceOperationsGroupedItem),
  220. 'id' => $ownerPriceOperationsGroupedItem->id,
  221. 'fee' => $fee,
  222. 'tax_fee' => $ownerStoreOutFeeReportsGroupByModelId[$ownerPriceOperationsGroupedItem->id][0]['tax_fee'] ?? 0,
  223. ];
  224. }
  225. }
  226. return $information;
  227. }
  228. /**
  229. * @param $owner
  230. * @param string|null $counting_month
  231. * @param array $ownerFeeTotal
  232. * @return array
  233. */
  234. private function buildExpressFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  235. {
  236. /**@var $expressFeeService OwnerLogisticFeeReportService */
  237. $expressFeeService = app('OwnerLogisticFeeReportService');
  238. $expressFeeTotal = $expressFeeService->getTotalFee($owner->id, $counting_month);
  239. $ownerFeeTotal ['expressFee'] = [
  240. 'fee' => $expressFeeTotal->fee ?? 0,
  241. 'tax_fee' => $expressFeeTotal->tax_fee ?? 0,
  242. ];
  243. return $ownerFeeTotal;
  244. }
  245. /**
  246. * @param $owner
  247. * @param string|null $counting_month
  248. * @param array $ownerFeeTotal
  249. * @return array
  250. */
  251. private function buildLogisticFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  252. {
  253. /**@var $waybillSettlementBillService OwnerWaybillSettlementBillService */
  254. $waybillSettlementBillService = app('OwnerWaybillSettlementBillService');
  255. $logisticFeeTotal = $waybillSettlementBillService->getTotalFee($owner->id, $counting_month);
  256. $ownerFeeTotal ['logisticFee'] = [
  257. 'fee' => $logisticFeeTotal->fee ?? 0,
  258. 'tax_fee' => $logisticFeeTotal->tax_fee ?? 0,
  259. ];
  260. return $ownerFeeTotal;
  261. }
  262. /**
  263. * @param $owner
  264. * @param string|null $counting_month
  265. * @param array $ownerFeeTotal
  266. * @return array
  267. */
  268. private function buildProcessFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  269. {
  270. /**@var $ownerProcessSettlementBillService OwnerProcessSettlementBillService */
  271. $ownerProcessSettlementBillService = app('OwnerProcessSettlementBillService');
  272. $processFeeTotal = $ownerProcessSettlementBillService->getTotalFee($owner->id, $counting_month);
  273. $ownerFeeTotal ['processFee'] = [
  274. 'fee' => $processFeeTotal->fee ?? 0,
  275. 'tax_fee' => $processFeeTotal->tax_fee ?? 0,
  276. ];
  277. return $ownerFeeTotal;
  278. }
  279. /**
  280. * @param string|null $counting_month
  281. * @param $owner
  282. * @param array $ownerFeeTotal
  283. * @return array
  284. */
  285. private function buildSystemFee(?string $counting_month, $owner, array $ownerFeeTotal): array
  286. {
  287. $ownerBillReport = OwnerBillReport::query()
  288. ->where('counting_month', $counting_month)
  289. ->where('owner_id', $owner->id)
  290. ->first();
  291. $ownerFeeTotal ['systemFee'] = [
  292. 'fee' => $ownerBillReport->other_fee ?? 0,
  293. 'tax_fee' => $ownerBillReport->other_tax_fee ?? 0,
  294. ];
  295. return $ownerFeeTotal;
  296. }
  297. /**
  298. * @param $owner
  299. * @param string|null $counting_month
  300. * @param array $ownerFeeTotal
  301. * @return array
  302. */
  303. private function buildSundryFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  304. {
  305. /**@var $ownerSundryFeeDetailService OwnerSundryFeeDetailService */
  306. $ownerSundryFeeDetailService = app('OwnerSundryFeeDetailService');
  307. $sundryFeeTotals = $ownerSundryFeeDetailService->getTotalFee($owner->id, $counting_month);
  308. if (!$sundryFeeTotals->isEmpty()) {
  309. foreach ($sundryFeeTotals as $sundryFeeTotal) {
  310. $ownerFeeTotal ['sundryFee'][] = [
  311. 'type' => $sundryFeeTotal->type,
  312. 'fee' => $sundryFeeTotal->fee,
  313. ];
  314. }
  315. } else {
  316. $ownerFeeTotal ['sundryFee'] = [];
  317. }
  318. return $ownerFeeTotal;
  319. }
  320. /**
  321. * @param string|null $counting_month
  322. * @param $owner
  323. * @param array $ownerFeeTotal
  324. * @return array
  325. */
  326. private function buildIndemnityFee(?string $counting_month, $owner, array $ownerFeeTotal): array
  327. {
  328. list($start, $end) = $this->getStartAndEnd($counting_month);
  329. $indemnityFee = OrderIssue::query()
  330. ->selectRaw("sum(baoshi_indemnity_money) as fee,owner_id,order_id")
  331. ->leftJoin('orders', 'order_issues.order_id', '=', 'orders.id')
  332. ->where('owner_id', $owner->id)
  333. ->whereBetween('order_issues.created_at', [$start, $end])->first();
  334. $ownerFeeTotal ['indemnityFee'] = [
  335. 'fee' => $indemnityFee->fee ?? 0,
  336. ];
  337. return $ownerFeeTotal;
  338. }
  339. /**
  340. * @param $owner
  341. * @param string|null $counting_month
  342. * @param array $ownerFeeTotal
  343. * @return array
  344. */
  345. private function buildPackingMaterialFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  346. {
  347. /**@var $packingMaterialFeeService OwnerProcurementSettlementBillService */
  348. $packingMaterialFeeService = app('OwnerProcurementSettlementBillService');
  349. $packingMaterialFee = $packingMaterialFeeService->getTotalFee($owner->id, $counting_month);
  350. $ownerFeeTotal ['packingMaterialFee'] = [
  351. 'fee' => $packingMaterialFee ?? 0,
  352. ];
  353. return $ownerFeeTotal;
  354. }
  355. /**
  356. * @param $owner
  357. * @param string|null $counting_month
  358. * @param array $ownerFeeTotal
  359. * @return array
  360. */
  361. private function buildUnloadFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  362. {
  363. /**@var $unloadService OwnerDischargeTaskSettlementBillService */
  364. $unloadService = app('OwnerDischargeTaskSettlementBillService');
  365. $unloadFee = $unloadService->getTotalFee($owner->id, $counting_month);
  366. $ownerFeeTotal ['unloadFee'] = [
  367. 'fee' => $unloadFee ?? 0,
  368. ];
  369. return $ownerFeeTotal;
  370. }
  371. /**
  372. * @param array $ownerFeeTotal
  373. * @return array
  374. */
  375. private function calTotalFeeAndTotalTaxFee(array $ownerFeeTotal): array
  376. {
  377. $totalFee = 0;
  378. $totalTaxFee = 0;
  379. foreach ($ownerFeeTotal as $key => $ownerFeeTotalItem) {
  380. if ($key == 'information') {
  381. list($totalFee, $totalTaxFee) = $this->calInformationTotalFeeAndTotalTaxFee($ownerFeeTotalItem, $totalFee, $totalTaxFee);
  382. } else if ($key == 'sundryFee') {
  383. foreach ($ownerFeeTotalItem as $sundryFeeItem) {
  384. $totalFee += $sundryFeeItem['fee'] ?? 0;
  385. }
  386. } else {
  387. $totalFee += $ownerFeeTotalItem['fee'] ?? 0;
  388. $totalTaxFee += $ownerFeeTotalItem['tax_fee'] ?? 0;
  389. }
  390. }
  391. $ownerFeeTotal['totalFee'] = $totalFee;
  392. $ownerFeeTotal['totalTaxFee'] = $totalTaxFee;
  393. return array($totalFee, $totalTaxFee, $ownerFeeTotal);
  394. }
  395. /**
  396. * @param $totalTaxFee
  397. * @param $totalFee
  398. * @param $ownerFeeTotal
  399. * @return mixed
  400. */
  401. private function calTaxRate($totalTaxFee, $totalFee, $ownerFeeTotal)
  402. {
  403. try {
  404. $taxRate = ($totalTaxFee / $totalFee) * 100 ?? 0;
  405. } catch (\Exception $e) {
  406. $taxRate = 0;
  407. }
  408. $ownerFeeTotal['taxRate'] = $taxRate;
  409. return $ownerFeeTotal;
  410. }
  411. /**
  412. * @param $owner
  413. * @param string|null $counting_month
  414. * @param $ownerFeeTotal
  415. * @return array
  416. */
  417. private function buildInsertData($owner, ?string $counting_month, $ownerFeeTotal): array
  418. {
  419. return [
  420. 'owner_id' => $owner->id,
  421. 'counting_month' => $counting_month,
  422. 'information' => $ownerFeeTotal['information'],
  423. 'fee' => $ownerFeeTotal['totalFee'],
  424. 'logistic_fee' => $ownerFeeTotal['logisticFee']['fee'],
  425. 'logistic_tax_fee' => $ownerFeeTotal['logisticFee']['tax_fee'],
  426. 'express_fee' => $ownerFeeTotal['expressFee']['fee'],
  427. 'express_tax_fee' => $ownerFeeTotal['expressFee']['tax_fee'],
  428. 'process_fee' => $ownerFeeTotal['processFee']['fee'],
  429. 'process_tax_fee' => $ownerFeeTotal['processFee']['tax_fee'],
  430. 'system_fee' => $ownerFeeTotal['systemFee']['fee'],
  431. 'system_tax_fee' => $ownerFeeTotal['systemFee']['tax_fee'],
  432. 'sundry_information' => $ownerFeeTotal['sundryFee'],
  433. 'packing_material_fee' => $ownerFeeTotal['packingMaterialFee']['fee'],
  434. 'unload_fee' => $ownerFeeTotal['unloadFee']['fee'],
  435. 'tax_rate' => $ownerFeeTotal['taxRate'],
  436. 'indemnity_fee' => $ownerFeeTotal['indemnityFee']['fee'],
  437. ];
  438. }
  439. /**
  440. * @param $ownerFeeTotalItem
  441. * @param $totalFee
  442. * @param $totalTaxFee
  443. * @return array|int[]
  444. */
  445. private function calInformationTotalFeeAndTotalTaxFee($ownerFeeTotalItem, $totalFee, $totalTaxFee): array
  446. {
  447. foreach ($ownerFeeTotalItem as $ownerFeeTotalItemOne) {
  448. foreach ($ownerFeeTotalItemOne as $feeItem) {
  449. $totalFee += $feeItem['fee'] ?? 0;
  450. $totalTaxFee += $feeItem['tax_fee'] ?? 0;
  451. }
  452. }
  453. return array($totalFee, $totalTaxFee);
  454. }
  455. /**
  456. * @param $owner
  457. * @param string|null $counting_month
  458. * @param array $insertData
  459. */
  460. private function createOrUpdate($owner, ?string $counting_month, array $insertData): void
  461. {
  462. if (OwnerFeeTotal::query()->where('owner_id', $owner->id)->where('counting_month', $counting_month)->exists()) {
  463. OwnerFeeTotal::query()
  464. ->where('owner_id', $owner->id)
  465. ->where('counting_month', $counting_month)
  466. ->update($insertData);
  467. } else {
  468. OwnerFeeTotal::query()
  469. ->where('owner_id', $owner->id)
  470. ->where('counting_month', $counting_month)
  471. ->create($insertData);
  472. }
  473. }
  474. }