OwnerFeeTotalService.php 19 KB

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