OwnerFeeTotalService.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  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. //获取特征信息
  133. $features = app("FeatureService")->getMapArray();
  134. OwnerPriceOperation::$features = $features;
  135. OwnerPriceOperationItem::$features = $features;
  136. foreach ($owner->ownerPriceOperations as &$operation) {
  137. $operation["featureFormat"] = $operation->featureFormat;
  138. $operation["isRejected"] = $operation->type_mark === 0;
  139. foreach ($operation->items as &$item) {
  140. $item["featureFormat"] = $item->featureFormat;
  141. if ($item["strategy"] == "起步") $item["type"] = $item["amount"] ? 0 : 1;
  142. }
  143. }
  144. $information = [
  145. //仓储
  146. 'storageFee' => [],
  147. //入库
  148. 'storeFee' => [],
  149. //出库
  150. 'storeOutFee' => [],
  151. ];
  152. //仓储
  153. foreach ($owner->ownerStoragePriceModels as $ownerStoragePriceModel) {
  154. /**@var $areaFeeService SettlementBillsAreaFeeService */
  155. $areaFeeService = app('SettlementBillsAreaFeeService');
  156. $remark = "起租面积:{$ownerStoragePriceModel->minimum_area},{$ownerStoragePriceModel->price[0]}元/{$ownerStoragePriceModel->unit->name}/{$ownerStoragePriceModel->timeUnit->name}";
  157. $information['storageFee'][] = [
  158. 'name' => $ownerStoragePriceModel->name,
  159. 'remark' => $remark,
  160. 'id' => $ownerStoragePriceModel->id,
  161. 'fee' => number_format($areaFeeService->getTotalFee($owner->id, $counting_month)->storage_fee ?? 0, 2),
  162. 'tax_fee' => $areaFeeService->getTotalFee($owner->id, $counting_month)->storage_tax_fee ?? 0
  163. ];
  164. }
  165. $ownerPriceOperationsGrouped = $owner->ownerPriceOperations->groupBy('operation_type');
  166. /**@var $storeOutFeeDetailsService OwnerStoreOutFeeDetailService */
  167. $storeOutFeeDetailsService = app('OwnerStoreOutFeeDetailService');
  168. $workFeeTotalGrouped = $storeOutFeeDetailsService->getTotalFee($owner->id, $counting_month)->groupBy('owner_price_operation_id');
  169. //入库
  170. foreach ($ownerPriceOperationsGrouped['入库'] ?? [] as $ownerPriceOperationsGroupedItem) {
  171. $information['storeFee'][] = [
  172. 'name' => $ownerPriceOperationsGroupedItem->name,
  173. 'remark' => $this->buildPriceRemarks($ownerPriceOperationsGroupedItem),
  174. 'id' => $ownerPriceOperationsGroupedItem->id,
  175. 'fee' => number_format($workFeeTotalGrouped[$ownerPriceOperationsGroupedItem->id][0]->work_fee ?? 0, 2),
  176. 'tax_fee' => $workFeeTotalGrouped[$ownerPriceOperationsGroupedItem->id][0]->work_tax_fee ?? 0,
  177. ];
  178. }
  179. //出库
  180. foreach ($ownerPriceOperationsGrouped['出库'] ?? [] as $ownerPriceOperationsGroupedItem) {
  181. $information['storeOutFee'][] = [
  182. 'name' => $ownerPriceOperationsGroupedItem->name,
  183. 'remark' => $this->buildPriceRemarks($ownerPriceOperationsGroupedItem),
  184. 'id' => $ownerPriceOperationsGroupedItem->id,
  185. 'fee' => number_format($workFeeTotalGrouped[$ownerPriceOperationsGroupedItem->id][0]->work_fee ?? 0, 2),
  186. 'tax_fee' => number_format($workFeeTotalGrouped[$ownerPriceOperationsGroupedItem->id][0]->work_tax_fee ?? 0, 2),
  187. ];
  188. }
  189. return $information;
  190. }
  191. /**
  192. * @param $owner
  193. * @param string|null $counting_month
  194. * @param array $ownerFeeTotal
  195. * @return array
  196. */
  197. private function buildExpressFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  198. {
  199. /**@var $expressFeeService OwnerLogisticFeeReportService */
  200. $expressFeeService = app('OwnerLogisticFeeReportService');
  201. $expressFeeTotal = $expressFeeService->getTotalFee($owner->id, $counting_month);
  202. $ownerFeeTotal ['expressFee'] = [
  203. 'fee' => $expressFeeTotal->fee ?? 0,
  204. 'tax_fee' => $expressFeeTotal->tax_fee ?? 0,
  205. ];
  206. return $ownerFeeTotal;
  207. }
  208. /**
  209. * @param $owner
  210. * @param string|null $counting_month
  211. * @param array $ownerFeeTotal
  212. * @return array
  213. */
  214. private function buildLogisticFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  215. {
  216. /**@var $waybillSettlementBillService OwnerWaybillSettlementBillService */
  217. $waybillSettlementBillService = app('OwnerWaybillSettlementBillService');
  218. $logisticFeeTotal = $waybillSettlementBillService->getTotalFee($owner->id, $counting_month);
  219. $ownerFeeTotal ['logisticFee'] = [
  220. 'fee' => $logisticFeeTotal->fee ?? 0,
  221. 'tax_fee' => $logisticFeeTotal->tax_fee ?? 0,
  222. ];
  223. return $ownerFeeTotal;
  224. }
  225. /**
  226. * @param $owner
  227. * @param string|null $counting_month
  228. * @param array $ownerFeeTotal
  229. * @return array
  230. */
  231. private function buildProcessFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  232. {
  233. /**@var $ownerProcessSettlementBillService OwnerProcessSettlementBillService */
  234. $ownerProcessSettlementBillService = app('OwnerProcessSettlementBillService');
  235. $processFeeTotal = $ownerProcessSettlementBillService->getTotalFee($owner->id, $counting_month);
  236. $ownerFeeTotal ['processFee'] = [
  237. 'fee' => $processFeeTotal->fee ?? 0,
  238. 'tax_fee' => $processFeeTotal->tax_fee ?? 0,
  239. ];
  240. return $ownerFeeTotal;
  241. }
  242. /**
  243. * @param string|null $counting_month
  244. * @param $owner
  245. * @param array $ownerFeeTotal
  246. * @return array
  247. */
  248. private function buildSystemFee(?string $counting_month, $owner, array $ownerFeeTotal): array
  249. {
  250. $ownerBillReport = OwnerBillReport::query()
  251. ->where('counting_month', $counting_month)
  252. ->where('owner_id', $owner->id)
  253. ->first();
  254. $ownerFeeTotal ['systemFee'] = [
  255. 'fee' => $ownerBillReport->other_fee ?? 0,
  256. 'tax_fee' => $ownerBillReport->other_tax_fee ?? 0,
  257. ];
  258. return $ownerFeeTotal;
  259. }
  260. /**
  261. * @param $owner
  262. * @param string|null $counting_month
  263. * @param array $ownerFeeTotal
  264. * @return array
  265. */
  266. private function buildSundryFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  267. {
  268. /**@var $ownerSundryFeeDetailService OwnerSundryFeeDetailService */
  269. $ownerSundryFeeDetailService = app('OwnerSundryFeeDetailService');
  270. $sundryFeeTotals = $ownerSundryFeeDetailService->getTotalFee($owner->id, $counting_month);
  271. if (!$sundryFeeTotals->isEmpty()) {
  272. foreach ($sundryFeeTotals as $sundryFeeTotal) {
  273. $ownerFeeTotal ['sundryFee'][] = [
  274. 'type' => $sundryFeeTotal->type,
  275. 'fee' => $sundryFeeTotal->fee,
  276. ];
  277. }
  278. } else {
  279. $ownerFeeTotal ['sundryFee'] = [];
  280. }
  281. return $ownerFeeTotal;
  282. }
  283. /**
  284. * @param string|null $counting_month
  285. * @param $owner
  286. * @param array $ownerFeeTotal
  287. * @return array
  288. */
  289. private function buildIndemnityFee(?string $counting_month, $owner, array $ownerFeeTotal): array
  290. {
  291. list($start, $end) = $this->getStartAndEnd($counting_month);
  292. $indemnityFee = OrderIssue::query()
  293. ->selectRaw("sum(baoshi_indemnity_money) as fee,owner_id,order_id")
  294. ->leftJoin('orders', 'order_issues.order_id', '=', 'orders.id')
  295. ->where('owner_id', $owner->id)
  296. ->whereBetween('order_issues.created_at', [$start, $end])->first();
  297. $ownerFeeTotal ['indemnityFee'] = [
  298. 'fee' => $indemnityFee->fee ?? 0,
  299. ];
  300. return $ownerFeeTotal;
  301. }
  302. /**
  303. * @param $owner
  304. * @param string|null $counting_month
  305. * @param array $ownerFeeTotal
  306. * @return array
  307. */
  308. private function buildPackingMaterialFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  309. {
  310. /**@var $packingMaterialFeeService OwnerProcurementSettlementBillService */
  311. $packingMaterialFeeService = app('OwnerProcurementSettlementBillService');
  312. $packingMaterialFee = $packingMaterialFeeService->getTotalFee($owner->id, $counting_month);
  313. $ownerFeeTotal ['packingMaterialFee'] = [
  314. 'fee' => $packingMaterialFee ?? 0,
  315. ];
  316. return $ownerFeeTotal;
  317. }
  318. /**
  319. * @param $owner
  320. * @param string|null $counting_month
  321. * @param array $ownerFeeTotal
  322. * @return array
  323. */
  324. private function buildUnloadFee($owner, ?string $counting_month, array $ownerFeeTotal): array
  325. {
  326. /**@var $unloadService OwnerDischargeTaskSettlementBillService */
  327. $unloadService = app('OwnerDischargeTaskSettlementBillService');
  328. $unloadFee = $unloadService->getTotalFee($owner->id, $counting_month);
  329. $ownerFeeTotal ['unloadFee'] = [
  330. 'fee' => $unloadFee ?? 0,
  331. ];
  332. return $ownerFeeTotal;
  333. }
  334. /**
  335. * @param array $ownerFeeTotal
  336. * @return array
  337. */
  338. private function calTotalFeeAndTotalTaxFee(array $ownerFeeTotal): array
  339. {
  340. $totalFee = 0;
  341. $totalTaxFee = 0;
  342. foreach ($ownerFeeTotal as $key => $ownerFeeTotalItem) {
  343. if ($key == 'information') {
  344. list($totalFee, $totalTaxFee) = $this->calInformationTotalFeeAndTotalTaxFee($ownerFeeTotalItem, $totalFee, $totalTaxFee);
  345. } else if ($key == 'sundryFee') {
  346. foreach ($ownerFeeTotalItem as $sundryFeeItem) {
  347. $totalFee += $sundryFeeItem['fee'] ?? 0;
  348. }
  349. } else {
  350. $totalFee += $ownerFeeTotalItem['fee'] ?? 0;
  351. $totalTaxFee += $ownerFeeTotalItem['tax_fee'] ?? 0;
  352. }
  353. }
  354. $ownerFeeTotal['totalFee'] = $totalFee;
  355. $ownerFeeTotal['totalTaxFee'] = $totalTaxFee;
  356. return array($totalFee, $totalTaxFee, $ownerFeeTotal);
  357. }
  358. /**
  359. * @param $totalTaxFee
  360. * @param $totalFee
  361. * @param $ownerFeeTotal
  362. * @return mixed
  363. */
  364. private function calTaxRate($totalTaxFee, $totalFee, $ownerFeeTotal)
  365. {
  366. try {
  367. $taxRate = number_format(($totalTaxFee / $totalFee) * 100, 2) ?? 0;
  368. } catch (\Exception $e) {
  369. $taxRate = 0;
  370. }
  371. $ownerFeeTotal['taxRate'] = $taxRate;
  372. return $ownerFeeTotal;
  373. }
  374. /**
  375. * @param $owner
  376. * @param string|null $counting_month
  377. * @param $ownerFeeTotal
  378. * @return array
  379. */
  380. private function buildInsertData($owner, ?string $counting_month, $ownerFeeTotal): array
  381. {
  382. return [
  383. 'owner_id' => $owner->id,
  384. 'counting_month' => $counting_month,
  385. 'information' => $ownerFeeTotal['information'],
  386. 'fee' => $ownerFeeTotal['totalFee'],
  387. 'logistic_fee' => $ownerFeeTotal['logisticFee']['fee'],
  388. 'logistic_tax_fee' => $ownerFeeTotal['logisticFee']['tax_fee'],
  389. 'express_fee' => $ownerFeeTotal['expressFee']['fee'],
  390. 'express_tax_fee' => $ownerFeeTotal['expressFee']['tax_fee'],
  391. 'process_fee' => $ownerFeeTotal['processFee']['fee'],
  392. 'process_tax_fee' => $ownerFeeTotal['processFee']['tax_fee'],
  393. 'system_fee' => $ownerFeeTotal['systemFee']['fee'],
  394. 'system_tax_fee' => $ownerFeeTotal['systemFee']['tax_fee'],
  395. 'sundry_information' => $ownerFeeTotal['sundryFee'],
  396. 'packing_material_fee' => $ownerFeeTotal['packingMaterialFee']['fee'],
  397. 'unload_fee' => $ownerFeeTotal['unloadFee']['fee'],
  398. 'tax_rate' => $ownerFeeTotal['taxRate'],
  399. 'indemnity_fee' => $ownerFeeTotal['indemnityFee']['fee'],
  400. ];
  401. }
  402. /**
  403. * @param $ownerFeeTotalItem
  404. * @param $totalFee
  405. * @param $totalTaxFee
  406. * @return array|int[]
  407. */
  408. private function calInformationTotalFeeAndTotalTaxFee($ownerFeeTotalItem, $totalFee, $totalTaxFee): array
  409. {
  410. foreach ($ownerFeeTotalItem as $ownerFeeTotalItemOne) {
  411. foreach ($ownerFeeTotalItemOne as $feeItem) {
  412. $totalFee += $feeItem['fee'] ?? 0;
  413. $totalTaxFee += $feeItem['tax_fee'] ?? 0;
  414. }
  415. }
  416. return array($totalFee, $totalTaxFee);
  417. }
  418. /**
  419. * @param $owner
  420. * @param string|null $counting_month
  421. * @param array $insertData
  422. */
  423. private function createOrUpdate($owner, ?string $counting_month, array $insertData): void
  424. {
  425. if (OwnerFeeTotal::query()->where('owner_id', $owner->id)->where('counting_month', $counting_month)->exists()) {
  426. OwnerFeeTotal::query()
  427. ->where('owner_id', $owner->id)
  428. ->where('counting_month', $counting_month)
  429. ->update($insertData);
  430. } else {
  431. OwnerFeeTotal::query()
  432. ->where('owner_id', $owner->id)
  433. ->where('counting_month', $counting_month)
  434. ->create($insertData);
  435. }
  436. }
  437. }