StatSaleClass.php 88 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735
  1. <?php
  2. namespace bizGhs\stat\classes;
  3. use biz\stat\classes\StatStockInClass;
  4. use biz\stat\classes\StatStockOutClass;
  5. use bizGhs\cg\classes\CgRefundClass;
  6. use bizGhs\custom\classes\CustomClass;
  7. use bizGhs\custom\classes\DistClass;
  8. use bizGhs\expend\classes\ExpendClass;
  9. use bizGhs\item\classes\ItemClassClass;
  10. use bizGhs\order\classes\OrderItemClass;
  11. use bizGhs\order\classes\PurchaseOrderClass;
  12. use bizGhs\order\classes\PurchaseOrderItemClass;
  13. use bizGhs\order\classes\RefundOrderClass;
  14. use bizGhs\order\classes\NextDayRefundClass;
  15. use bizGhs\order\classes\StockWastageOrderClass;
  16. use bizGhs\product\classes\ProductClass;
  17. use bizGhs\staff\classes\SalaryClass;
  18. use bizHd\goods\classes\PlantCgClass;
  19. use bizHd\order\classes\OrderClass as HdOrderClass;
  20. use bizGhs\order\classes\OrderClass;
  21. use bizHd\purchase\classes\PurchaseClass;
  22. use bizHd\refund\classes\HdRefundClass;
  23. use common\components\arrayUtil;
  24. use common\components\dateUtil;
  25. use common\components\dict;
  26. use common\components\util;
  27. use Yii;
  28. use bizGhs\base\classes\BaseClass;
  29. class StatSaleClass extends BaseClass
  30. {
  31. public static $baseFile = '\bizGhs\stat\models\StatSale';
  32. public static function wastage($mainId)
  33. {
  34. $get = Yii::$app->request->get();
  35. $where = [];
  36. $where['mainId'] = $mainId;
  37. $searchTime = isset($get['searchTime']) && !empty($get['searchTime']) ? $get['searchTime'] : 'today';
  38. $startTime = $get['startTime'] ?? '';
  39. $endTime = $get['endTime'] ?? '';
  40. $period = dateUtil::formatTime($searchTime, $startTime, $endTime, true);
  41. $start = $period['startTime'];
  42. $end = $period['endTime'];
  43. $currentStartDate = date('Y-m-d', strtotime($start));
  44. $currentEndDate = date('Y-m-d', strtotime($end));
  45. $currentStartTime = $currentStartDate . ' 00:00:00';
  46. $currentEndTime = $currentEndDate . ' 23:59:59';
  47. $where['addTime'] = ['between', [$currentStartTime, $currentEndTime]];
  48. $list = StockWastageOrderClass::getAllByCondition($where, null, '*');
  49. $totalPrice = 0;
  50. $totalCost = 0;
  51. if (!empty($list)) {
  52. foreach ($list as $order) {
  53. $price = $order['price'] ?? 0;
  54. $totalPrice = bcadd($totalPrice, $price, 2);
  55. $cost = $order['cost'] ?? 0;
  56. $totalCost = bcadd($totalCost, $cost, 2);
  57. }
  58. }
  59. $totalPrice = floatval($totalPrice);
  60. return ['totalPrice' => $totalPrice, 'totalCost' => $totalCost];
  61. }
  62. //结账跟踪 ssh 20230503
  63. public static function OrderClear($mainId)
  64. {
  65. $get = Yii::$app->request->get();
  66. $where = ['mainId' => $mainId, 'status' => ['in', [OrderClass::ORDER_STATUS_UN_SEND, OrderClass::ORDER_STATUS_SENDING, OrderClass::ORDER_STATUS_COMPLETE]]];
  67. $timeStyle = $get['timeStyle'] ?? 0;
  68. if (isset($get['searchTime']) && !empty($get['searchTime'])) {
  69. $searchTime = $get['searchTime'];
  70. $startTime = $get['startTime'] ?? '';
  71. $endTime = $get['endTime'] ?? '';
  72. $period = dateUtil::formatTime($searchTime, $startTime, $endTime, true);
  73. $start = $period['startTime'];
  74. $end = $period['endTime'];
  75. $currentStartDate = date('Y-m-d', strtotime($start));
  76. $currentEndDate = date('Y-m-d', strtotime($end));
  77. $currentStartTime = $currentStartDate . ' 00:00:00';
  78. $currentEndTime = $currentEndDate . ' 23:59:59';
  79. if ($timeStyle == 0) {
  80. $where['payTime'] = ['between', [$currentStartTime, $currentEndTime]];
  81. } else {
  82. $where['clearTime'] = ['between', [$currentStartTime, $currentEndTime]];
  83. }
  84. } else {
  85. $payTime = 'today';
  86. $startTime = $get['startTime'] ?? '';
  87. $endTime = $get['endTime'] ?? '';
  88. $period = dateUtil::formatTime($payTime, $startTime, $endTime, true);
  89. $start = $period['startTime'];
  90. $end = $period['endTime'];
  91. $currentStartDate = date('Y-m-d', strtotime($start));
  92. $currentEndDate = date('Y-m-d', strtotime($end));
  93. $currentStartTime = $currentStartDate . ' 00:00:00';
  94. $currentEndTime = $currentEndDate . ' 23:59:59';
  95. $where['payTime'] = ['between', [$currentStartTime, $currentEndTime]];
  96. }
  97. $customId = $get['customId'] ?? 0;
  98. if (!empty($customId)) {
  99. $where['customId'] = $customId;
  100. }
  101. $unClear = $get['unClear'] ?? 0;
  102. if ($unClear == 1) {
  103. $where['clearId'] = 0;
  104. $where['remainDebtPrice>'] = 0;
  105. }
  106. $ghsOrderList = OrderClass::getAllByCondition($where, null, '*');
  107. return ['list' => $ghsOrderList];
  108. }
  109. //客户下单榜 ssh 20230502
  110. public static function statCustomCg($mainId)
  111. {
  112. $get = Yii::$app->request->get();
  113. $where = [];
  114. $where['mainId'] = $mainId;
  115. $searchTime = !empty($get['searchTime']) ? $get['searchTime'] : 'today';
  116. $startTime = $get['startTime'] ?? '';
  117. $endTime = $get['endTime'] ?? '';
  118. $period = dateUtil::formatTime($searchTime, $startTime, $endTime, true);
  119. $start = $period['startTime'];
  120. $end = $period['endTime'];
  121. $where['time'] = ['between', [$start, $end]];
  122. $currentStartDate = date('Y-m-d', strtotime($start));
  123. $currentEndDate = date('Y-m-d', strtotime($end));
  124. $currentStartTime = $currentStartDate . ' 00:00:00';
  125. $currentEndTime = $currentEndDate . ' 23:59:59';
  126. $where = ['mainId' => $mainId, 'status' => ['in', [OrderClass::ORDER_STATUS_UN_SEND, OrderClass::ORDER_STATUS_SENDING, OrderClass::ORDER_STATUS_COMPLETE]]];
  127. $where['payTime'] = ['between', [$currentStartTime, $currentEndTime]];
  128. $customList = CustomClass::getAllByCondition(['ownMainId' => $mainId], null, 'id,name,py', 'id');
  129. $arr = [];
  130. $ghsOrderList = OrderClass::getAllByCondition($where, null, '*');
  131. $totalAmount = 0;
  132. $totalNum = 0;
  133. $totalProfit = 0;
  134. $totalCost = 0;
  135. if (!empty($ghsOrderList)) {
  136. foreach ($ghsOrderList as $ghsKey => $ghsOrder) {
  137. $actPrice = $ghsOrder['actPrice'] ?? 0;
  138. if ($actPrice <= 0) {
  139. continue;
  140. }
  141. $cost = $ghsOrder['remainCost'] ?? 0;
  142. $profit = bcsub($actPrice, $cost, 2);
  143. $orderPrice = $ghsOrder['orderPrice'] ?? 0;
  144. $tkPrice = $ghsOrder['tkPrice'] ?? 0;
  145. $customId = $ghsOrder['customId'] ?? 0;
  146. $status = $ghsOrder['status'] ?? 0;
  147. $book = $ghsOrder['book'] ?? 0;
  148. //扎数
  149. $count = $ghsOrder['itemNum'] ?? 0;
  150. if ($status == 1 || $status == 5) {
  151. continue;
  152. }
  153. if ($book == 1 && $status == 2) {
  154. continue;
  155. }
  156. $customName = $customList[$customId]['name'] ?? '';
  157. $py = $customList[$customId]['py'] ?? '';
  158. $totalNum++;
  159. $totalAmount = bcadd($totalAmount, $actPrice, 2);
  160. $totalProfit = bcadd($totalProfit, $profit, 2);
  161. $totalCost = bcadd($totalCost, $cost, 2);
  162. if (isset($arr[$customId])) {
  163. $arr[$customId]['num']++;
  164. $arr[$customId]['amount'] = bcadd($arr[$customId]['amount'], $actPrice, 2);
  165. $arr[$customId]['count'] = bcadd($arr[$customId]['count'], $count, 2);
  166. $arr[$customId]['orderPrice'] = bcadd($arr[$customId]['orderPrice'], $orderPrice, 2);
  167. $arr[$customId]['tkPrice'] = bcadd($arr[$customId]['tkPrice'], $tkPrice, 2);
  168. $arr[$customId]['cost'] = bcadd($arr[$customId]['cost'], $cost, 2);
  169. $arr[$customId]['profit'] = bcadd($arr[$customId]['profit'], $profit, 2);
  170. } else {
  171. $arr[$customId] = [
  172. 'customId' => $customId,
  173. 'customName' => $customName,
  174. 'py' => $py,
  175. 'num' => 1,
  176. 'count' => $count,
  177. 'amount' => $actPrice,
  178. 'levelName' => '',
  179. 'orderPrice' => $orderPrice,
  180. 'tkPrice' => $tkPrice,
  181. 'cost' => $cost,
  182. 'profit' => $profit,
  183. ];
  184. }
  185. }
  186. }
  187. // 隔天售后:按通过日扣金额/扎数;无当日开单也建负行(笔数不减)
  188. $fwdMap = NextDayRefundClass::sumAmountGroupByCustom($mainId, $currentStartTime, $currentEndTime);
  189. $qtyMap = NextDayRefundClass::sumItemQtyByCustom($mainId, $currentStartTime, $currentEndTime);
  190. $cidKeys = array_unique(array_merge(array_keys($fwdMap), array_keys($qtyMap)));
  191. foreach ($cidKeys as $cid) {
  192. $amt = $fwdMap[$cid] ?? '0';
  193. $qty = $qtyMap[$cid] ?? '0';
  194. if (bccomp((string)$amt, '0', 2) == 0 && bccomp((string)$qty, '0', 2) == 0) {
  195. continue;
  196. }
  197. if (!isset($arr[$cid])) {
  198. $arr[$cid] = [
  199. 'customId' => $cid,
  200. 'customName' => $customList[$cid]['name'] ?? '',
  201. 'py' => $customList[$cid]['py'] ?? '',
  202. 'num' => 0,
  203. 'count' => '0.00',
  204. 'amount' => '0.00',
  205. 'levelName' => '',
  206. 'orderPrice' => 0,
  207. 'tkPrice' => 0,
  208. 'cost' => 0,
  209. 'profit' => '0.00',
  210. ];
  211. }
  212. $arr[$cid]['amount'] = bcsub((string)$arr[$cid]['amount'], (string)$amt, 2);
  213. $arr[$cid]['profit'] = bcsub((string)$arr[$cid]['profit'], (string)$amt, 2);
  214. $arr[$cid]['count'] = bcsub((string)($arr[$cid]['count'] ?? 0), (string)$qty, 2);
  215. $totalAmount = bcsub((string)$totalAmount, (string)$amt, 2);
  216. $totalProfit = bcsub((string)$totalProfit, (string)$amt, 2);
  217. }
  218. if (!empty($arr)) {
  219. $arr = arrayUtil::arraySort($arr, 'profit');
  220. }
  221. $totalAmount = floatval($totalAmount);
  222. return ['list' => $arr, 'totalAmount' => $totalAmount, 'totalNum' => $totalNum, 'totalCost' => $totalCost, 'totalProfit' => $totalProfit];
  223. }
  224. public static function profile($mainId)
  225. {
  226. //收入:批发开单、零售开单(含门店、美团和微信客服)、出库
  227. //支出:采购、调拨入库、批发退款、零售退款、店租、水电、伙食
  228. $get = Yii::$app->request->get();
  229. $where = [];
  230. $where['mainId'] = $mainId;
  231. $searchTime = isset($get['searchTime']) && !empty($get['searchTime']) ? $get['searchTime'] : 'today';
  232. $startTime = $get['startTime'] ?? '';
  233. $endTime = $get['endTime'] ?? '';
  234. $period = dateUtil::formatTime($searchTime, $startTime, $endTime, true);
  235. $start = $period['startTime'];
  236. $end = $period['endTime'];
  237. $where['time'] = ['between', [$start, $end]];
  238. $currentStartDate = date('Y-m-d', strtotime($start));
  239. $currentEndDate = date('Y-m-d', strtotime($end));
  240. $currentStartTime = $currentStartDate . ' 00:00:00';
  241. $currentEndTime = $currentEndDate . ' 23:59:59';
  242. //出库
  243. $stockOut = StatStockOutClass::getSum($where);
  244. //采购入库
  245. $cgWhere = ['mainId' => $mainId, 'status' => 4];
  246. $cgWhere['entryTime'] = ['between', [$currentStartTime, $currentEndTime]];
  247. $cgList = PurchaseOrderClass::getAllByCondition($cgWhere, null, '*');
  248. $cg = 0;
  249. if (!empty($cgList)) {
  250. foreach ($cgList as $cgKey => $cgItem) {
  251. $actPrice = $cgItem['actPrice'] ?? 0;
  252. $paidPrice = $cgItem['paidPrice'] ?? 0;
  253. if ($actPrice <= 0) {
  254. // 如果$actPrice=0,表示这个采购单已经全部退款,不需要再统计成本,本来$paidPrice要同步清零,但没有,这个问题由徐州邂逅花坊马总,提出的需求发现
  255. $cg = bcadd($cg, 0, 2);
  256. } else {
  257. $total = bcadd($actPrice, $paidPrice, 2);
  258. //物流费用不算成本。意思是说,长短途运费+提货费+本地运费,这四项和打包费一起,参与到平摊花材运费成本的计算,但那四项不参与总的采购成本登记,因为,有另外地方会独立登记运费成本。
  259. //$paidPrice 字段说明,此字段表示收货方已付款金额,包括 $localCharge本地运费、 $pickCharge提货费、 $shortCharge短途运费(到付时算,如果不是到付,不算在$paidPrice里)、$longCharge长途运费(到付时算,如果不是到付,不算在$paidPrice里)
  260. //请搜索关键词 cg_item_cost ,有多处相似情况要考虑
  261. if (isset($cgItem['isCost']) && $cgItem['isCost'] == 0) {
  262. $shortCharge = $cgItem['shortCharge'] ?? 0;
  263. $longCharge = $cgItem['longCharge'] ?? 0;
  264. $pickCharge = $cgItem['pickCharge'] ?? 0;
  265. $localCharge = $cgItem['localCharge'] ?? 0;
  266. $a1 = bcadd($shortCharge, $longCharge, 2);
  267. $a2 = bcadd($pickCharge, $localCharge, 2);
  268. $a = bcadd($a1, $a2, 2);
  269. //注意下面是减号 bcsub
  270. $total = bcsub($total, $a, 2);
  271. }
  272. $cg = bcadd($cg, $total, 2);
  273. }
  274. }
  275. }
  276. $cg = floatval($cg);
  277. $lsCgWhere = ['mainId' => $mainId, 'status' => 4, 'belongCost' => 1];
  278. $lsCgWhere['payTime'] = ['between', [$currentStartTime, $currentEndTime]];
  279. $lsCgList = PurchaseClass::getAllByCondition($lsCgWhere, null, '*');
  280. $lsCgAmount = 0;
  281. if (!empty($lsCgList)) {
  282. foreach ($lsCgList as $lsCgItem) {
  283. $actPrice = $lsCgItem['actPrice'] ?? 0;
  284. $lsCgAmount = bcadd($lsCgAmount, $actPrice, 2);
  285. }
  286. }
  287. $lsCgAmount = floatval($lsCgAmount);
  288. $lzWhere = ['mainId' => $mainId, 'status' => 3];
  289. $lzWhere['entryTime'] = ['between', [$currentStartTime, $currentEndTime]];
  290. $lzCgList = PlantCgClass::getAllByCondition($lzWhere, null, '*');
  291. $lzCgAmount = 0;
  292. if (!empty($lzCgList)) {
  293. foreach ($lzCgList as $lzInfo) {
  294. $actPrice = $lzInfo['actPrice'] ?? 0;
  295. $lzCgAmount = bcadd($actPrice, $lzCgAmount, 2);
  296. }
  297. }
  298. $lzCgAmount = floatval($lzCgAmount);
  299. //调拨入库
  300. $stockIn = StatStockInClass::getSum($where);
  301. $totalOrderNum = 0;
  302. //批发开单
  303. $pfIncome = 0;
  304. $pfSendCost = 0;
  305. $pfPack = 0;
  306. $where = ['mainId' => $mainId, 'status' => ['in', [OrderClass::ORDER_STATUS_UN_SEND, OrderClass::ORDER_STATUS_SENDING, OrderClass::ORDER_STATUS_COMPLETE]]];
  307. $where['payTime'] = ['between', [$currentStartTime, $currentEndTime]];
  308. $ghsOrderList = OrderClass::getAllByCondition($where, null, '*');
  309. if (!empty($ghsOrderList)) {
  310. foreach ($ghsOrderList as $ghsKey => $ghsOrder) {
  311. $actPrice = $ghsOrder['actPrice'] ?? 0;
  312. $sendCost = $ghsOrder['sendCost'] ?? 0;
  313. $refundSendCost = $ghsOrder['refundSendCost'] ?? 0;
  314. $remainSendCost = bcsub($sendCost, $refundSendCost, 2);
  315. $packCost = $ghsOrder['packCost'] ?? 0;
  316. $refundPackCost = $ghsOrder['refundPackCost'] ?? 0;
  317. $remainPackCost = bcsub($packCost, $refundPackCost, 2);
  318. $pfIncome = bcadd($pfIncome, $actPrice, 2);
  319. $pfSendCost = bcadd($pfSendCost, $remainSendCost, 2);
  320. $pfPack = bcadd($pfPack, $remainPackCost, 2);
  321. $totalOrderNum++;
  322. }
  323. }
  324. // 隔天售后扣减批发收入(笔数不变)
  325. $pfIncome = bcsub(
  326. (string)$pfIncome,
  327. NextDayRefundClass::sumAmountByMainAndTime($mainId, $currentStartTime, $currentEndTime),
  328. 2
  329. );
  330. //零售开单
  331. $payCodeIncome = 0;
  332. $lsAfterSale = 0;
  333. $lsGiveBalance = 0;
  334. $lsIncome = 0;
  335. $lsSendCost = 0;
  336. $lsServiceFee = 0;
  337. $hdWhere = ['mainId' => $mainId, 'status' => ['in', [HdOrderClass::ORDER_STATUS_UN_SEND, HdOrderClass::ORDER_STATUS_SENDING, HdOrderClass::ORDER_STATUS_COMPLETE]]];
  338. $hdWhere['payTime'] = ['between', [$currentStartTime, $currentEndTime]];
  339. $hdOrderList = HdOrderClass::getAllByCondition($hdWhere, null, '*');
  340. foreach ($hdOrderList as $hdKey => $hdOrder) {
  341. $actPrice = $hdOrder['mainPay'] ?? 0;
  342. $onlinePay = $hdOrder['onlinePay'] ?? 1;
  343. $repeat = $hdOrder['repeat'] ?? 0;
  344. $forward = $hdOrder['forward'] ?? 0;
  345. if ($hdOrder['tkPrice'] && $hdOrder['tkPrice'] > 0) {
  346. $actPrice = bcsub($actPrice, $hdOrder['tkPrice'], 2);
  347. }
  348. if ($forward == 1) {
  349. //零售售后付款
  350. $lsAfterSale = bcadd($lsAfterSale, $actPrice, 2);
  351. } else {
  352. $cash = $hdOrder['cash'] ?? 0;
  353. $serviceFee = $hdOrder['serviceFee'] ?? 0;
  354. $sendCost = $hdOrder['sendCost'] ?? 0;
  355. $lsIncome = bcadd($actPrice, $lsIncome, 2);
  356. $lsIncome = bcadd($lsIncome, $cash, 2);
  357. //如果$actPrice<=0,则退款取消先不计算成本
  358. if ($actPrice > 0) {
  359. $lsSendCost = bcadd($lsSendCost, $sendCost, 2);
  360. $lsServiceFee = bcadd($lsServiceFee, $serviceFee, 2);
  361. }
  362. $totalOrderNum++;
  363. if ($onlinePay == 2 && floatval($cash) <= 0 && $repeat == 1) {
  364. $payCodeIncome = bcadd($payCodeIncome, $actPrice, 2);
  365. $payCodeIncome = floatval($payCodeIncome);
  366. }
  367. $giveBalance = $hdOrder['giveBalance'] ?? 0;
  368. $giveBalanceTk = $hdOrder['giveBalanceTk'] ?? 0;
  369. $remainGiveBalance = bcsub($giveBalance, $giveBalanceTk, 2);
  370. $lsGiveBalance = bcadd($lsGiveBalance, $remainGiveBalance, 2);
  371. }
  372. }
  373. $condition = ['mainId' => $mainId, 'addTime' => ['between', [$currentStartTime, $currentEndTime]],];
  374. $salary = 0;
  375. $salaryList = SalaryClass::getAllByCondition($condition, null, '*', null, true);
  376. if (!empty($salaryList)) {
  377. foreach ($salaryList as $item) {
  378. $salary = bcadd($salary, $item->amount, 2);
  379. }
  380. }
  381. $condition = [
  382. 'mainId' => $mainId,
  383. 'payTime' => ['between', [$currentStartTime, $currentEndTime]],
  384. 'delStatus' => 0,
  385. ];
  386. $expendList = ExpendClass::getAllByCondition($condition, null, '*', null, true);
  387. $expendTypeMap = dict::getDict('expendTypeMap');
  388. $expendAmount = [];
  389. if (!empty($expendList)) {
  390. foreach ($expendList as $item) {
  391. $type = $item->type ?? 0;
  392. $amount = $item->amount ?? 0;
  393. $name = $expendTypeMap[$type] ?? '暂无';
  394. if (!isset($expendAmount[$type]['amount'])) {
  395. $expendAmount[$type]['amount'] = 0;
  396. }
  397. $expendAmount[$type]['name'] = $name;
  398. $expendAmount[$type]['amount'] = floatval(bcadd($expendAmount[$type]['amount'], $amount, 2));
  399. }
  400. }
  401. $income = [
  402. ['name' => '批发', 'id' => 'pf', 'amount' => floatval($pfIncome)],
  403. ['name' => '零售', 'id' => 'ls', 'amount' => floatval($lsIncome)],
  404. ['name' => '调拨出库', 'id' => 'allot', 'amount' => floatval($stockOut)],
  405. ];
  406. $expend = [
  407. ['name' => '批发运费', 'id' => 'pfSendCost', 'amount' => floatval($pfSendCost)],
  408. ['name' => '批发包装费', 'id' => 'pfSendCost', 'amount' => floatval($pfPack)],
  409. ['name' => '零售运费', 'id' => 'lsSendCost', 'amount' => floatval($lsSendCost)],
  410. ['name' => '零售售后付款', 'id' => 'lsSendCost', 'amount' => floatval($lsAfterSale)],
  411. ['name' => '美团手续费', 'id' => 'mtFee', 'amount' => floatval($lsServiceFee)],
  412. ['name' => '花材采购', 'id' => 'cg', 'amount' => floatval($cg)],
  413. ['name' => '绿植资材采购', 'id' => 'cg', 'amount' => floatval($lzCgAmount)],
  414. ['name' => '零售花材采购', 'id' => 'cg', 'amount' => floatval($lsCgAmount)],
  415. ['name' => '调拨入库', 'id' => 'allot', 'amount' => floatval($stockIn)],
  416. ['name' => '员工工资', 'id' => 'salary', 'amount' => floatval($salary)],
  417. ['name' => '收款码收入', 'id' => 'salary', 'amount' => floatval($payCodeIncome)],
  418. ['name' => '零售充值赠送', 'id' => 'salary', 'amount' => floatval($lsGiveBalance)],
  419. ];
  420. if (!empty($expendAmount)) {
  421. foreach ($expendAmount as $it) {
  422. $expend[] = $it;
  423. }
  424. }
  425. $balance = 0;
  426. foreach ($income as $it) {
  427. $amount = $it['amount'] ?? 0;
  428. $balance = bcadd($amount, $balance, 2);
  429. }
  430. foreach ($expend as $it) {
  431. $amount = $it['amount'] ?? 0;
  432. $balance = bcsub($balance, $amount, 2);
  433. }
  434. return ['income' => $income, 'expend' => $expend, 'balance' => floatval($balance), 'totalOrderNum' => $totalOrderNum];
  435. }
  436. //按花材统计收入 ssh 20231111
  437. public static function incomeOutItem($mainId)
  438. {
  439. $get = Yii::$app->request->get();
  440. $export = $get['export'] ?? 0;
  441. $where = [];
  442. $where['mainId'] = $mainId;
  443. $searchTime = isset($get['searchTime']) && !empty($get['searchTime']) ? $get['searchTime'] : 'today';
  444. $startTime = $get['startTime'] ?? '';
  445. $endTime = $get['endTime'] ?? '';
  446. $period = dateUtil::formatTime($searchTime, $startTime, $endTime, true);
  447. $start = $period['startTime'];
  448. $end = $period['endTime'];
  449. $where['time'] = ['between', [$start, $end]];
  450. $currentStartDate = date('Y-m-d', strtotime($start));
  451. $currentEndDate = date('Y-m-d', strtotime($end));
  452. $currentStartTime = $currentStartDate . ' 00:00:00';
  453. $currentEndTime = $currentEndDate . ' 23:59:59';
  454. $s = strtotime($currentStartTime);
  455. $e = strtotime($currentEndTime);
  456. $p = bcsub($e, $s);
  457. $xx = bcmul(86400, 90);
  458. if ($p > $xx) {
  459. util::fail('查询时间不能超过三个月,编号666');
  460. }
  461. $productList = ProductClass::getAllByCondition(['mainId' => $mainId], null, 'id,name', 'id');
  462. if (empty($productList)) {
  463. util::fail('没有找到花材');
  464. }
  465. $arr = [];
  466. //打包费和运费
  467. $packFreight = 0;
  468. $onlyRefundCg = 0;
  469. $onlyRefund = 0;
  470. $totalDiscountAmount = 0;
  471. $totalLabourCost = 0;
  472. //采购入库
  473. $tbCgIncome = [];
  474. $tbCgIncomeStaff = [];
  475. $cgWhere = ['mainId' => $mainId, 'status' => 4];
  476. $cgWhere['entryTime'] = ['between', [$currentStartTime, $currentEndTime]];
  477. $cgList = PurchaseOrderClass::getAllByCondition($cgWhere, null, '*');
  478. if (!empty($cgList)) {
  479. foreach ($cgList as $cgKey => $cgItem) {
  480. $packingCharge = $cgItem['packingCharge'] ?? 0;
  481. $shortCharge = $cgItem['shortCharge'] ?? 0;
  482. $longCharge = $cgItem['longCharge'] ?? 0;
  483. $pickCharge = $cgItem['pickCharge'] ?? 0;
  484. $localCharge = $cgItem['localCharge'] ?? 0;
  485. $packFreight = bcadd($packFreight, $packingCharge, 2);
  486. $packFreight = bcadd($packFreight, $shortCharge, 2);
  487. $packFreight = bcadd($packFreight, $longCharge, 2);
  488. $packFreight = bcadd($packFreight, $pickCharge, 2);
  489. $packFreight = bcadd($packFreight, $localCharge, 2);
  490. $tkPrice = $cgItem['tkPrice'] ?? 0;
  491. $orderSn = $cgItem['orderSn'] ?? '';
  492. $cgItemInfoList = PurchaseOrderItemClass::getAllByCondition(['orderSn' => $orderSn], null, '*', null, true);
  493. if (!empty($cgItemInfoList)) {
  494. foreach ($cgItemInfoList as $cgData) {
  495. $itemNum = $cgData->itemNum ?? 0;
  496. $productId = $cgData->productId ?? 0;
  497. $refundNum = $cgData->refundNum ?? 0;
  498. $remainNum = bcsub($itemNum, $refundNum);
  499. $bigPrice = $cgData->bigPrice ?? 0;
  500. $amount = bcmul($remainNum, $bigPrice, 2);
  501. $itemName = $productList[$productId]['name'] ?? '已删除';
  502. $arr[$productId]['name'] = $itemName;
  503. $arr[$productId]['id'] = $productId;
  504. if (isset($arr[$productId]['expend'])) {
  505. $arr[$productId]['expend'] = bcadd($amount, $arr[$productId]['expend'], 2);
  506. $arr[$productId]['outNum'] = bcadd($arr[$productId]['outNum'], $remainNum, 2);
  507. } else {
  508. $arr[$productId]['expend'] = $amount;
  509. $arr[$productId]['outNum'] = $remainNum;
  510. $arr[$productId]['inNum'] = 0;
  511. $arr[$productId]['income'] = 0;
  512. }
  513. }
  514. if ($tkPrice > 0) {
  515. $cgRefundOrderList = CgRefundClass::getAllByCondition(['relateOrderSn' => $orderSn], null, '*', null, true);
  516. if (!empty($cgRefundOrderList)) {
  517. foreach ($cgRefundOrderList as $cgRefundOrder) {
  518. if ($cgRefundOrder->refundType == 2) {
  519. $onlyRefundCg = bcadd($cgRefundOrder->refundPrice, $onlyRefundCg, 2);
  520. }
  521. }
  522. }
  523. }
  524. }
  525. }
  526. }
  527. //批发开单
  528. $pfIncome = 0;
  529. $tbSaleIncome = [];
  530. $tbSaleIncomeStaff = [];
  531. $where = ['mainId' => $mainId, 'status' => ['in', [OrderClass::ORDER_STATUS_UN_SEND, OrderClass::ORDER_STATUS_SENDING, OrderClass::ORDER_STATUS_COMPLETE]]];
  532. $where['payTime'] = ['between', [$currentStartTime, $currentEndTime]];
  533. $ghsOrderList = OrderClass::getAllByCondition($where, null, '*');
  534. if (!empty($ghsOrderList)) {
  535. foreach ($ghsOrderList as $ghsKey => $ghsOrder) {
  536. $book = $ghsOrder['book'] ?? 0;
  537. $status = $ghsOrder['status'] ?? 0;
  538. if ($book == 1 && $status == 2) {
  539. //预订单待发货的不算收入
  540. continue;
  541. }
  542. if ($status == 0 || $status == 5) {
  543. continue;
  544. }
  545. $shopAdminId = $ghsOrder['shopAdminId'] ?? 0;
  546. $shopAdminName = $ghsOrder['shopAdminName'] ?? '';
  547. $orderSn = $ghsOrder['orderSn'] ?? '';
  548. $actPrice = $ghsOrder['actPrice'] ?? 0;
  549. $tkPrice = $ghsOrder['tkPrice'] ?? 0;
  550. $pfIncome = bcadd($pfIncome, $actPrice, 2);
  551. $labourCost = $ghsOrder['labourCost'] ?? 0;
  552. $discountAmount = $ghsOrder['discountAmount'] ?? 0;
  553. $totalLabourCost = bcadd($labourCost, $totalLabourCost, 2);
  554. $totalDiscountAmount = bcadd($totalDiscountAmount, $discountAmount, 2);
  555. $orderItemList = OrderItemClass::getAllByCondition(['orderSn' => $orderSn], null, '*', null, true);
  556. if (!empty($orderItemList)) {
  557. foreach ($orderItemList as $orderItem) {
  558. $refundNum = $orderItem->refundNum ?? 0;
  559. $name = $orderItem->name ?? '';
  560. $productId = $orderItem->productId ?? 0;
  561. $num = $orderItem->xhNum ?? 0;
  562. // 支付日净销量:当天已退=refundNum-nextRefundNum
  563. $remainNum = NextDayRefundClass::payDayRemainNum(
  564. $num,
  565. $refundNum,
  566. $orderItem->nextRefundNum ?? 0
  567. );
  568. $xhUnitPrice = $orderItem->xhUnitPrice ?? 0;
  569. $amount = bcmul($remainNum, $xhUnitPrice, 2);
  570. $itemName = $productList[$productId]['name'] ?? '已删除';
  571. $arr[$productId]['name'] = $itemName;
  572. $arr[$productId]['id'] = $productId;
  573. if (isset($arr[$productId]['income'])) {
  574. $arr[$productId]['income'] = bcadd($amount, $arr[$productId]['income'], 2);
  575. $arr[$productId]['inNum'] = bcadd($arr[$productId]['inNum'], $remainNum, 2);
  576. } else {
  577. $arr[$productId]['expend'] = 0;
  578. $arr[$productId]['outNum'] = 0;
  579. $arr[$productId]['inNum'] = $remainNum;
  580. $arr[$productId]['income'] = $amount;
  581. }
  582. //单独统计
  583. $belongCost = $orderItem->belongCost ?? 0;
  584. if ($belongCost == 1) {
  585. if (isset($tbSaleIncome[$productId])) {
  586. $tbSaleIncome[$productId]['num'] = bcadd($tbSaleIncome[$productId]['num'], $remainNum);
  587. $tbSaleIncome[$productId]['price'] = bcadd($tbSaleIncome[$productId]['price'], $amount, 2);
  588. } else {
  589. $tbSaleIncome[$productId] = ['name' => $name, 'num' => $remainNum, 'price' => $amount];
  590. }
  591. if (isset($tbSaleIncomeStaff[$productId]) && isset($tbSaleIncomeStaff[$productId][$shopAdminId])) {
  592. $tbSaleIncomeStaff[$productId][$shopAdminId]['num'] = bcadd($tbSaleIncomeStaff[$productId][$shopAdminId]['num'], $remainNum);
  593. $tbSaleIncomeStaff[$productId][$shopAdminId]['price'] = bcadd($tbSaleIncomeStaff[$productId][$shopAdminId]['price'], $amount, 2);
  594. } else {
  595. $tbSaleIncomeStaff[$productId][$shopAdminId] = ['name' => $name, 'num' => $remainNum, 'price' => $amount, 'staffName' => $shopAdminName];
  596. }
  597. }
  598. }
  599. if ($tkPrice > 0) {
  600. $refundList = RefundOrderClass::getAllByCondition(['relateOrderSn' => $orderSn], null, '*', null, true);
  601. if (!empty($refundList)) {
  602. foreach ($refundList as $refund) {
  603. if ($refund->refundType == 1) {
  604. //退货退款前面已经考虑,这里不再处理 OK
  605. } else {
  606. // 隔天仅退款记在通过日,这里跳过避免与下方 sumMoneyOnly 重复
  607. if (intval($refund->sameDay ?? RefundOrderClass::SAME_DAY_YES) === RefundOrderClass::SAME_DAY_NO) {
  608. continue;
  609. }
  610. $onlyRefund = bcadd($onlyRefund, $refund->refundPrice, 2);
  611. }
  612. }
  613. }
  614. }
  615. }
  616. }
  617. }
  618. // 隔天售后:支付日已用 nextRefundNum;通过日再扣数量/金额;仅退款并入销售仅退款
  619. $onlyRefund = bcadd(
  620. (string)$onlyRefund,
  621. self::applyNextDayAdjustToProductIncomeRows(
  622. $arr,
  623. $tbSaleIncome,
  624. $productList,
  625. $mainId,
  626. $currentStartTime,
  627. $currentEndTime
  628. ),
  629. 2
  630. );
  631. //零售开单
  632. $lsIncome = 0;
  633. $hdWhere = ['mainId' => $mainId, 'status' => ['in', [HdOrderClass::ORDER_STATUS_UN_SEND, HdOrderClass::ORDER_STATUS_SENDING, HdOrderClass::ORDER_STATUS_COMPLETE]]];
  634. $hdWhere['payTime'] = ['between', [$currentStartTime, $currentEndTime]];
  635. $hdOrderList = HdOrderClass::getAllByCondition($hdWhere, null, '*');
  636. foreach ($hdOrderList as $hdKey => $hdOrder) {
  637. $actPrice = $hdOrder['mainPay'] ?? 0;
  638. $cash = $hdOrder['cash'] ?? 0;
  639. $lsIncome = bcadd($actPrice, $lsIncome, 2);
  640. $lsIncome = bcadd($lsIncome, $cash, 2);
  641. $orderSn = $hdOrder['orderSn'] ?? '';
  642. $tkPrice = $hdOrder['tkPrice'] ?? 0;
  643. $orderItemList = \bizHd\order\classes\OrderItemClass::getAllByCondition(['orderSn' => $orderSn], null, '*', null, true);
  644. if (!empty($orderItemList)) {
  645. foreach ($orderItemList as $orderItem) {
  646. $unitPrice = $orderItem->unitPrice ?? 0;
  647. $refundNum = $orderItem->refundNum ?? 0;
  648. $num = $orderItem->num ?? 0;
  649. $productId = $orderItem->itemId ?? 0;
  650. $remainNum = bcsub($num, $refundNum);
  651. $amount = bcmul($remainNum, $unitPrice, 2);
  652. $itemName = $productList[$productId]['name'] ?? '已删除';
  653. $arr[$productId]['name'] = $itemName;
  654. $arr[$productId]['id'] = $productId;
  655. if (isset($arr[$productId]['income'])) {
  656. $arr[$productId]['income'] = bcadd($amount, $arr[$productId]['income'], 2);
  657. $arr[$productId]['inNum'] = bcadd($arr[$productId]['inNum'], $remainNum, 2);
  658. } else {
  659. $arr[$productId]['expend'] = 0;
  660. $arr[$productId]['outNum'] = 0;
  661. $arr[$productId]['inNum'] = $remainNum;
  662. $arr[$productId]['income'] = $amount;
  663. }
  664. }
  665. if ($tkPrice > 0) {
  666. $refundList = HdRefundClass::getAllByCondition(['orderSn' => $orderSn], null, '*', null, true);
  667. if (!empty($refundList)) {
  668. foreach ($refundList as $refund) {
  669. if ($refund->refundType == 2) {
  670. $onlyRefund = bcadd($onlyRefund, $refund->refundPrice, 2);
  671. }
  672. }
  673. }
  674. }
  675. }
  676. }
  677. $totalIncome = 0;
  678. $totalExpend = 0;
  679. if (!empty($arr)) {
  680. foreach ($arr as $key => $val) {
  681. $income = $val['income'] ?? 0;
  682. $income = floatval($income);
  683. $totalIncome = bcadd($totalIncome, $income, 2);
  684. $expend = $val['expend'] ?? 0;
  685. $expend = floatval($expend);
  686. $totalExpend = bcadd($totalExpend, $expend, 2);
  687. $profit = bcsub($income, $expend, 2);
  688. $arr[$key]['profit'] = floatval($profit);
  689. $arr[$key]['income'] = floatval($income);
  690. $arr[$key]['expend'] = floatval($expend);
  691. }
  692. }
  693. //总成本算上物流打包等费用
  694. $totalExpend = bcadd($totalExpend, $packFreight, 2);
  695. //总收入算上采购仅退款
  696. $totalIncome = bcadd($totalIncome, $onlyRefundCg, 2);
  697. //总收入加上人工费
  698. $totalIncome = bcadd($totalIncome, $totalLabourCost, 2);
  699. //总收入减掉优惠金额
  700. $totalIncome = bcsub($totalIncome, $totalDiscountAmount, 2);
  701. //总成本算上销售仅退款
  702. $totalExpend = bcadd($totalExpend, $onlyRefund, 2);
  703. $totalProfit = bcsub($totalIncome, $totalExpend, 2);
  704. $totalIncome = floatval($totalIncome);
  705. $totalExpend = floatval($totalExpend);
  706. $totalProfit = floatval($totalProfit);
  707. $arr = array_values($arr);
  708. $arr = arrayUtil::arraySort($arr, 'profit');
  709. if ($export == 1) {
  710. $statData = [
  711. ['id' => 0, 'name' => '物流打包费', 'income' => 0, 'expend' => $packFreight, 'profit' => -$packFreight, 'inNum' => 0, 'outNum' => 0],
  712. ['id' => 0, 'name' => '采购仅退款', 'income' => $onlyRefundCg, 'expend' => 0, 'profit' => $onlyRefundCg, 'inNum' => 0, 'outNum' => 0],
  713. ['id' => 0, 'name' => '销售仅退款', 'income' => 0, 'expend' => $onlyRefund, 'profit' => -$onlyRefund, 'inNum' => 0, 'outNum' => 0],
  714. ['id' => 0, 'name' => '附加人工费', 'income' => $totalLabourCost, 'expend' => 0, 'profit' => $totalLabourCost, 'inNum' => 0, 'outNum' => 0],
  715. ['id' => 0, 'name' => '优惠金额', 'income' => -$totalDiscountAmount, 'expend' => 0, 'profit' => -$totalDiscountAmount, 'inNum' => 0, 'outNum' => 0],
  716. ['id' => 0, 'name' => '【汇总金额】', 'income' => $totalIncome, 'expend' => $totalExpend, 'profit' => $totalProfit, 'inNum' => 0, 'outNum' => 0],
  717. ];
  718. $list = array_merge($arr, $statData);
  719. self::exportIncomeOutItem($list, $mainId);
  720. }
  721. util::success(['list' => $arr, 'packFreight' => $packFreight, 'onlyRefundCg' => $onlyRefundCg, 'onlyRefund' => $onlyRefund,
  722. 'totalIncome' => $totalIncome,
  723. 'totalExpend' => $totalExpend,
  724. 'totalProfit' => $totalProfit,
  725. 'tbSaleIncome' => $tbSaleIncome,
  726. 'tbCgIncome' => $tbCgIncome,
  727. 'tbCgIncomeStaff' => $tbCgIncomeStaff,
  728. 'tbSaleIncomeStaff' => $tbSaleIncomeStaff,
  729. 'totalLabourCost' => $totalLabourCost,
  730. 'totalDiscountAmount' => $totalDiscountAmount,
  731. ]);
  732. }
  733. //按分类统计收入 ssh 20231111
  734. public static function classProfile($mainId)
  735. {
  736. $get = Yii::$app->request->get();
  737. $export = $get['export'] ?? 0;
  738. $where = [];
  739. $where['mainId'] = $mainId;
  740. $searchTime = isset($get['searchTime']) && !empty($get['searchTime']) ? $get['searchTime'] : 'today';
  741. $startTime = $get['startTime'] ?? '';
  742. $endTime = $get['endTime'] ?? '';
  743. $period = dateUtil::formatTime($searchTime, $startTime, $endTime, true);
  744. $start = $period['startTime'];
  745. $end = $period['endTime'];
  746. $where['time'] = ['between', [$start, $end]];
  747. $currentStartDate = date('Y-m-d', strtotime($start));
  748. $currentEndDate = date('Y-m-d', strtotime($end));
  749. $currentStartTime = $currentStartDate . ' 00:00:00';
  750. $currentEndTime = $currentEndDate . ' 23:59:59';
  751. $s = strtotime($currentStartTime);
  752. $e = strtotime($currentEndTime);
  753. $p = bcsub($e, $s);
  754. $xx = bcmul(86400, 90);
  755. if ($p > $xx) {
  756. util::fail('查询时间不能超过三个月,编号780');
  757. }
  758. $classList = ItemClassClass::getAllByCondition(['mainId' => $mainId], null, 'id,name', 'id');
  759. if (empty($classList)) {
  760. util::fail('没有找到花材');
  761. }
  762. $arr = [];
  763. //打包费和运费
  764. $packFreight = 0;
  765. $onlyRefundCg = 0;
  766. $onlyRefund = 0;
  767. $totalDiscountAmount = 0;
  768. $totalLabourCost = 0;
  769. //采购入库
  770. $tbCgIncome = [];
  771. $tbCgIncomeStaff = [];
  772. $cgWhere = ['mainId' => $mainId, 'status' => 4];
  773. $cgWhere['entryTime'] = ['between', [$currentStartTime, $currentEndTime]];
  774. $cgList = PurchaseOrderClass::getAllByCondition($cgWhere, null, '*');
  775. if (!empty($cgList)) {
  776. foreach ($cgList as $cgKey => $cgItem) {
  777. $packingCharge = $cgItem['packingCharge'] ?? 0;
  778. $shortCharge = $cgItem['shortCharge'] ?? 0;
  779. $longCharge = $cgItem['longCharge'] ?? 0;
  780. $pickCharge = $cgItem['pickCharge'] ?? 0;
  781. $localCharge = $cgItem['localCharge'] ?? 0;
  782. $cgStaffId = $cgItem['cgStaffId'] ?? 0;
  783. $cgStaffName = $cgItem['cgStaffName'] ?? '';
  784. $actPrice = $cgItem['actPrice'] ?? 0;
  785. if ($actPrice <= 0) {
  786. continue;
  787. }
  788. $packFreight = bcadd($packFreight, $packingCharge, 2);
  789. $packFreight = bcadd($packFreight, $shortCharge, 2);
  790. $packFreight = bcadd($packFreight, $longCharge, 2);
  791. $packFreight = bcadd($packFreight, $pickCharge, 2);
  792. $packFreight = bcadd($packFreight, $localCharge, 2);
  793. $tkPrice = $cgItem['tkPrice'] ?? 0;
  794. $orderSn = $cgItem['orderSn'] ?? '';
  795. $cgItemInfoList = PurchaseOrderItemClass::getAllByCondition(['orderSn' => $orderSn], null, '*', null, true);
  796. if (!empty($cgItemInfoList)) {
  797. foreach ($cgItemInfoList as $cgData) {
  798. $itemNum = $cgData->itemNum ?? 0;
  799. $productId = $cgData->productId ?? 0;
  800. $name = $cgData->name ?? '';
  801. $refundNum = $cgData->refundNum ?? 0;
  802. $remainNum = bcsub($itemNum, $refundNum);
  803. $bigPrice = $cgData->bigPrice ?? 0;
  804. $amount = bcmul($remainNum, $bigPrice, 2);
  805. $classId = $cgData->classId;
  806. $className = $classList[$classId]['name'] ?? '已删除';
  807. if ($className == '运费') {
  808. //noticeUtil::push("{$cgData->orderSn}运费项", '15280215347');
  809. }
  810. $arr[$classId]['className'] = $className;
  811. $arr[$classId]['classId'] = $classId;
  812. if (isset($arr[$classId]['expend'])) {
  813. $arr[$classId]['expend'] = bcadd($amount, $arr[$classId]['expend'], 2);
  814. $arr[$classId]['cgNum'] = bcadd($arr[$classId]['cgNum'], $remainNum);
  815. } else {
  816. $arr[$classId]['expend'] = $amount;
  817. $arr[$classId]['income'] = 0;
  818. $arr[$classId]['cgNum'] = $remainNum;
  819. $arr[$classId]['saleNum'] = 0;
  820. }
  821. //单独统计
  822. $belongCost = $cgData->belongCost ?? 0;
  823. if ($belongCost == 1) {
  824. if (isset($tbCgIncome[$productId])) {
  825. $tbCgIncome[$productId]['num'] = bcadd($tbCgIncome[$productId]['num'], $remainNum);
  826. $tbCgIncome[$productId]['price'] = bcadd($tbCgIncome[$productId]['price'], $amount, 2);
  827. } else {
  828. $tbCgIncome[$productId] = ['num' => $remainNum, 'name' => $name, 'price' => $amount];
  829. }
  830. if (isset($tbCgIncomeStaff[$productId]) && isset($tbCgIncomeStaff[$productId][$cgStaffId])) {
  831. $tbCgIncomeStaff[$productId][$cgStaffId]['num'] = bcadd($tbCgIncomeStaff[$productId][$cgStaffId]['num'], $remainNum);
  832. $tbCgIncomeStaff[$productId][$cgStaffId]['price'] = bcadd($tbCgIncomeStaff[$productId][$cgStaffId]['price'], $amount, 2);
  833. } else {
  834. $tbCgIncomeStaff[$productId][$cgStaffId] = ['num' => $remainNum, 'name' => $name, 'price' => $amount, 'staffName' => $cgStaffName,];
  835. }
  836. }
  837. }
  838. if ($tkPrice > 0) {
  839. $cgRefundOrderList = CgRefundClass::getAllByCondition(['relateOrderSn' => $orderSn], null, '*', null, true);
  840. if (!empty($cgRefundOrderList)) {
  841. foreach ($cgRefundOrderList as $cgRefundOrder) {
  842. if ($cgRefundOrder->refundType == 2) {
  843. $onlyRefundCg = bcadd($cgRefundOrder->refundPrice, $onlyRefundCg, 2);
  844. }
  845. }
  846. }
  847. }
  848. }
  849. }
  850. }
  851. //批发开单
  852. $pfIncome = 0;
  853. $tbSaleIncome = [];
  854. $tbSaleIncomeStaff = [];
  855. $where = ['mainId' => $mainId, 'status' => ['in', [OrderClass::ORDER_STATUS_UN_SEND, OrderClass::ORDER_STATUS_SENDING, OrderClass::ORDER_STATUS_COMPLETE]]];
  856. $where['payTime'] = ['between', [$currentStartTime, $currentEndTime]];
  857. $ghsOrderList = OrderClass::getAllByCondition($where, null, '*');
  858. if (!empty($ghsOrderList)) {
  859. foreach ($ghsOrderList as $ghsKey => $ghsOrder) {
  860. $book = $ghsOrder['book'] ?? 0;
  861. $status = $ghsOrder['status'] ?? 0;
  862. if ($book == 1 && $status == 2) {
  863. //预订单待发货的不算收入
  864. continue;
  865. }
  866. if ($status == 0 || $status == 5) {
  867. continue;
  868. }
  869. $shopAdminId = $ghsOrder['shopAdminId'] ?? 0;
  870. $shopAdminName = $ghsOrder['shopAdminName'] ?? '';
  871. $orderSn = $ghsOrder['orderSn'] ?? '';
  872. $actPrice = $ghsOrder['actPrice'] ?? 0;
  873. if ($actPrice <= 0) {
  874. continue;
  875. }
  876. $tkPrice = $ghsOrder['tkPrice'] ?? 0;
  877. $pfIncome = bcadd($pfIncome, $actPrice, 2);
  878. $labourCost = $ghsOrder['labourCost'] ?? 0;
  879. $discountAmount = $ghsOrder['discountAmount'] ?? 0;
  880. $totalLabourCost = bcadd($labourCost, $totalLabourCost, 2);
  881. $totalDiscountAmount = bcadd($totalDiscountAmount, $discountAmount, 2);
  882. $orderItemList = OrderItemClass::getAllByCondition(['orderSn' => $orderSn], null, '*', null, true);
  883. if (!empty($orderItemList)) {
  884. foreach ($orderItemList as $orderItem) {
  885. $refundNum = $orderItem->refundNum ?? 0;
  886. $name = $orderItem->name ?? '';
  887. $productId = $orderItem->productId ?? 0;
  888. $num = $orderItem->xhNum ?? 0;
  889. $remainNum = NextDayRefundClass::payDayRemainNum(
  890. $num,
  891. $refundNum,
  892. $orderItem->nextRefundNum ?? 0
  893. );
  894. $classId = $orderItem->classId ?? 0;
  895. $className = $classList[$classId]['name'] ?? '已删除';
  896. $xhUnitPrice = $orderItem->xhUnitPrice ?? 0;
  897. $amount = bcmul($remainNum, $xhUnitPrice, 2);
  898. $arr[$classId]['className'] = $className;
  899. $arr[$classId]['classId'] = $classId;
  900. if (isset($arr[$classId]['income'])) {
  901. $arr[$classId]['income'] = bcadd($amount, $arr[$classId]['income'], 2);
  902. $arr[$classId]['saleNum'] = bcadd($arr[$classId]['saleNum'], $remainNum);
  903. } else {
  904. $arr[$classId]['expend'] = 0;
  905. $arr[$classId]['income'] = $amount;
  906. $arr[$classId]['saleNum'] = $remainNum;
  907. $arr[$classId]['cgNum'] = 0;
  908. }
  909. //单独统计
  910. $belongCost = $orderItem->belongCost ?? 0;
  911. if ($belongCost == 1) {
  912. if (isset($tbSaleIncome[$productId])) {
  913. $tbSaleIncome[$productId]['num'] = bcadd($tbSaleIncome[$productId]['num'], $remainNum);
  914. $tbSaleIncome[$productId]['price'] = bcadd($tbSaleIncome[$productId]['price'], $amount, 2);
  915. } else {
  916. $tbSaleIncome[$productId] = ['name' => $name, 'num' => $remainNum, 'price' => $amount];
  917. }
  918. if (isset($tbSaleIncomeStaff[$productId]) && isset($tbSaleIncomeStaff[$productId][$shopAdminId])) {
  919. $tbSaleIncomeStaff[$productId][$shopAdminId]['num'] = bcadd($tbSaleIncomeStaff[$productId][$shopAdminId]['num'], $remainNum);
  920. $tbSaleIncomeStaff[$productId][$shopAdminId]['price'] = bcadd($tbSaleIncomeStaff[$productId][$shopAdminId]['price'], $amount, 2);
  921. } else {
  922. $tbSaleIncomeStaff[$productId][$shopAdminId] = ['name' => $name, 'num' => $remainNum, 'price' => $amount, 'staffName' => $shopAdminName];
  923. }
  924. }
  925. }
  926. if ($tkPrice > 0) {
  927. $refundList = RefundOrderClass::getAllByCondition(['relateOrderSn' => $orderSn], null, '*', null, true);
  928. if (!empty($refundList)) {
  929. foreach ($refundList as $refund) {
  930. if ($refund->refundType == 1) {
  931. //退货退款前面已经考虑,这里不再处理 OK
  932. } else {
  933. // 隔天仅退款记在通过日,这里跳过避免与下方 sumMoneyOnly 重复
  934. if (intval($refund->sameDay ?? RefundOrderClass::SAME_DAY_YES) === RefundOrderClass::SAME_DAY_NO) {
  935. continue;
  936. }
  937. $onlyRefund = bcadd($onlyRefund, $refund->refundPrice, 2);
  938. }
  939. }
  940. }
  941. }
  942. }
  943. }
  944. }
  945. // 隔天售后:支付日已用 nextRefundNum;通过日再按售后单扣分类收入;仅退款进「销售仅退款」
  946. $productClassMap = ProductClass::getAllByCondition(['mainId' => $mainId], null, 'id,classId', 'id');
  947. $applyClassDelta = function ($pidMap, $sign) use (&$arr, &$classList, $productClassMap) {
  948. foreach ($pidMap as $pid => $row) {
  949. $classId = $productClassMap[$pid]['classId'] ?? 0;
  950. $deltaNum = bcmul((string)($row['num'] ?? '0'), (string)$sign, 2);
  951. $deltaAmt = bcmul((string)($row['amount'] ?? '0'), (string)$sign, 2);
  952. if (!isset($arr[$classId])) {
  953. if (bccomp($deltaAmt, '0', 2) == 0 && bccomp($deltaNum, '0', 2) == 0) {
  954. continue;
  955. }
  956. $arr[$classId] = [
  957. 'className' => $classList[$classId]['name'] ?? '已删除',
  958. 'classId' => $classId,
  959. 'expend' => 0,
  960. 'income' => '0.00',
  961. 'saleNum' => '0.00',
  962. 'cgNum' => 0,
  963. ];
  964. }
  965. $arr[$classId]['income'] = bcadd((string)($arr[$classId]['income'] ?? 0), $deltaAmt, 2);
  966. $arr[$classId]['saleNum'] = bcadd((string)($arr[$classId]['saleNum'] ?? 0), $deltaNum, 2);
  967. }
  968. };
  969. $applyClassDelta(
  970. NextDayRefundClass::sumItemByProduct($mainId, $currentStartTime, $currentEndTime),
  971. -1
  972. );
  973. $onlyRefund = bcadd(
  974. (string)$onlyRefund,
  975. NextDayRefundClass::sumMoneyOnlyAmountByMainAndTime($mainId, $currentStartTime, $currentEndTime),
  976. 2
  977. );
  978. //零售开单
  979. $lsIncome = 0;
  980. $hdWhere = ['mainId' => $mainId, 'status' => ['in', [HdOrderClass::ORDER_STATUS_UN_SEND, HdOrderClass::ORDER_STATUS_SENDING, HdOrderClass::ORDER_STATUS_COMPLETE]]];
  981. $hdWhere['payTime'] = ['between', [$currentStartTime, $currentEndTime]];
  982. $hdOrderList = HdOrderClass::getAllByCondition($hdWhere, null, '*');
  983. foreach ($hdOrderList as $hdKey => $hdOrder) {
  984. $actPrice = $hdOrder['mainPay'] ?? 0;
  985. $cash = $hdOrder['cash'] ?? 0;
  986. if ($actPrice <= 0 && $cash <= 0) {
  987. continue;
  988. }
  989. $lsIncome = bcadd($actPrice, $lsIncome, 2);
  990. $lsIncome = bcadd($lsIncome, $cash, 2);
  991. $orderSn = $hdOrder['orderSn'] ?? '';
  992. $tkPrice = $hdOrder['tkPrice'] ?? 0;
  993. $orderItemList = \bizHd\order\classes\OrderItemClass::getAllByCondition(['orderSn' => $orderSn], null, '*', null, true);
  994. if (!empty($orderItemList)) {
  995. foreach ($orderItemList as $orderItem) {
  996. $classId = $orderItem->classId ?? 0;
  997. $unitPrice = $orderItem->unitPrice ?? 0;
  998. $refundNum = $orderItem->refundNum ?? 0;
  999. $num = $orderItem->num ?? 0;
  1000. $productId = $orderItem->itemId ?? 0;
  1001. $name = $orderItem->name ?? '';
  1002. $remainNum = bcsub($num, $refundNum);
  1003. $amount = bcmul($remainNum, $unitPrice, 2);
  1004. $className = $classList[$classId]['name'] ?? '已删除';
  1005. $arr[$classId]['className'] = $className;
  1006. $arr[$classId]['classId'] = $classId;
  1007. if (isset($arr[$classId]['income'])) {
  1008. $arr[$classId]['income'] = bcadd($amount, $arr[$classId]['income'], 2);
  1009. $arr[$classId]['saleNum'] = bcadd($arr[$classId]['saleNum'], $remainNum);
  1010. } else {
  1011. $arr[$classId]['expend'] = 0;
  1012. $arr[$classId]['income'] = $amount;
  1013. $arr[$classId]['saleNum'] = $remainNum;
  1014. $arr[$classId]['cgNum'] = 0;
  1015. }
  1016. $belongCost = $orderItem->belongCost ?? 0;
  1017. if ($belongCost == 1) {
  1018. if (isset($tbSaleIncome[$productId])) {
  1019. $tbSaleIncome[$productId]['num'] = bcadd($tbSaleIncome[$productId]['num'], $remainNum);
  1020. $tbSaleIncome[$productId]['price'] = bcadd($tbSaleIncome[$productId]['price'], $amount, 2);
  1021. } else {
  1022. $tbSaleIncome[$productId] = ['name' => $name, 'num' => $remainNum, 'price' => $amount];
  1023. }
  1024. }
  1025. }
  1026. if ($tkPrice > 0) {
  1027. $refundList = HdRefundClass::getAllByCondition(['orderSn' => $orderSn], null, '*', null, true);
  1028. if (!empty($refundList)) {
  1029. foreach ($refundList as $refund) {
  1030. if ($refund->refundType == 2) {
  1031. $onlyRefund = bcadd($onlyRefund, $refund->refundPrice, 2);
  1032. }
  1033. }
  1034. }
  1035. }
  1036. }
  1037. }
  1038. $totalIncome = 0;
  1039. $totalExpend = 0;
  1040. if (!empty($arr)) {
  1041. foreach ($arr as $key => $val) {
  1042. $income = $val['income'] ?? 0;
  1043. $income = floatval($income);
  1044. $totalIncome = bcadd($totalIncome, $income, 2);
  1045. $expend = $val['expend'] ?? 0;
  1046. $expend = floatval($expend);
  1047. $totalExpend = bcadd($totalExpend, $expend, 2);
  1048. $profit = bcsub($income, $expend, 2);
  1049. $arr[$key]['profit'] = floatval($profit);
  1050. $arr[$key]['income'] = floatval($income);
  1051. $arr[$key]['expend'] = floatval($expend);
  1052. }
  1053. }
  1054. //总成本算上物流打包等费用
  1055. $totalExpend = bcadd($totalExpend, $packFreight, 2);
  1056. //总收入算上采购仅退款
  1057. $totalIncome = bcadd($totalIncome, $onlyRefundCg, 2);
  1058. //总收入加上人工费
  1059. $totalIncome = bcadd($totalIncome, $totalLabourCost, 2);
  1060. //总收入减掉优惠金额
  1061. $totalIncome = bcsub($totalIncome, $totalDiscountAmount, 2);
  1062. //总成本算上销售仅退款
  1063. $totalExpend = bcadd($totalExpend, $onlyRefund, 2);
  1064. $totalProfit = bcsub($totalIncome, $totalExpend, 2);
  1065. $totalIncome = floatval($totalIncome);
  1066. $totalExpend = floatval($totalExpend);
  1067. $totalProfit = floatval($totalProfit);
  1068. $arr = array_values($arr);
  1069. $arr = arrayUtil::arraySort($arr, 'profit');
  1070. if ($export == 1) {
  1071. $statData = [
  1072. ['classId' => 0, 'className' => '物流打包费', 'income' => 0, 'expend' => $packFreight, 'profit' => -$packFreight, 'saleNum' => 0, 'cgNum' => 0],
  1073. ['classId' => 0, 'className' => '采购仅退款', 'income' => $onlyRefundCg, 'expend' => 0, 'profit' => $onlyRefundCg, 'saleNum' => 0, 'cgNum' => 0],
  1074. ['classId' => 0, 'className' => '销售仅退款', 'income' => 0, 'expend' => $onlyRefund, 'profit' => -$onlyRefund, 'saleNum' => 0, 'cgNum' => 0],
  1075. ['classId' => 0, 'className' => '附加人工费', 'income' => $totalLabourCost, 'expend' => 0, 'profit' => $totalLabourCost, 'saleNum' => 0, 'cgNum' => 0],
  1076. ['classId' => 0, 'className' => '优惠金额', 'income' => -$totalDiscountAmount, 'expend' => 0, 'profit' => -$totalDiscountAmount, 'saleNum' => 0, 'cgNum' => 0],
  1077. ['classId' => 0, 'className' => '【汇总金额】', 'income' => $totalIncome, 'expend' => $totalExpend, 'profit' => $totalProfit, 'saleNum' => 0, 'cgNum' => 0],
  1078. ];
  1079. $list = array_merge($arr, $statData);
  1080. self::exportIncomeClass($list, $mainId);
  1081. }
  1082. util::success(['list' => $arr, 'packFreight' => $packFreight, 'onlyRefundCg' => $onlyRefundCg, 'onlyRefund' => $onlyRefund,
  1083. 'totalIncome' => $totalIncome,
  1084. 'totalExpend' => $totalExpend,
  1085. 'totalProfit' => $totalProfit,
  1086. 'tbSaleIncome' => $tbSaleIncome,
  1087. 'tbCgIncome' => $tbCgIncome,
  1088. 'tbCgIncomeStaff' => $tbCgIncomeStaff,
  1089. 'tbSaleIncomeStaff' => $tbSaleIncomeStaff,
  1090. 'totalLabourCost' => $totalLabourCost,
  1091. 'totalDiscountAmount' => $totalDiscountAmount,
  1092. ]);
  1093. }
  1094. public static function exportIncomeOutItem($list, $mainId)
  1095. {
  1096. $phpExcelFile = Yii::getAlias("@vendor/phpoffice/phpexcel/");
  1097. require_once($phpExcelFile . 'Classes/PHPExcel.php');
  1098. $objPHPExcel = new \PHPExcel();
  1099. $objPHPExcel->getProperties()->setCreator("Maarten Balliauw")
  1100. ->setLastModifiedBy("Maarten Balliauw")
  1101. ->setTitle("Office 2007 XLSX Document")
  1102. ->setSubject("Office 2007 XLSX Document")
  1103. ->setDescription("Test document for Office 2007 XLSX, generated using PHP classes.")
  1104. ->setKeywords("office 2007 openxml php")
  1105. ->setCategory("file");
  1106. $ghsTitle = '供货商';
  1107. $objPHPExcel->getActiveSheet()->getHeaderFooter()->setOddHeader(date('n月j日') . " " . $ghsTitle);
  1108. $objPHPExcel->getActiveSheet()->getPageMargins()->setTop(0.7);
  1109. $objPHPExcel->getActiveSheet()->getPageMargins()->setBottom(0.1);
  1110. $objPHPExcel->getActiveSheet()->getPageMargins()->setLeft(0.5);
  1111. $objPHPExcel->getActiveSheet()->getPageMargins()->setRight(0);
  1112. $objPHPExcel->getActiveSheet()->getPageMargins()->setHeader(0.1);
  1113. $objPHPExcel->getActiveSheet()->getPageMargins()->setFooter(0);
  1114. $objPHPExcel->getActiveSheet()->setCellValue('A1', '名称');
  1115. $objPHPExcel->getActiveSheet()->setCellValue('B1', '销售收入');
  1116. $objPHPExcel->getActiveSheet()->setCellValue('C1', '销售数量');
  1117. $objPHPExcel->getActiveSheet()->setCellValue('D1', '采购成本');
  1118. $objPHPExcel->getActiveSheet()->setCellValue('E1', '采购数量');
  1119. $objPHPExcel->getActiveSheet()->setCellValue('F1', '利润');
  1120. //设置宽度
  1121. $objPHPExcel->getActiveSheet()->getColumnDimension('A')->setWidth(30);
  1122. $objPHPExcel->getActiveSheet()->getColumnDimension('B')->setWidth(20);
  1123. $objPHPExcel->getActiveSheet()->getColumnDimension('C')->setWidth(20);
  1124. $objPHPExcel->getActiveSheet()->getColumnDimension('C')->setWidth(20);
  1125. //加粗
  1126. $objPHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setSize(9)->setBold(true);
  1127. $objPHPExcel->getActiveSheet()->getStyle('B1')->getFont()->setSize(9)->setBold(true);
  1128. $objPHPExcel->getActiveSheet()->getStyle('C1')->getFont()->setSize(9)->setBold(true);
  1129. $objPHPExcel->getActiveSheet()->getStyle('D1')->getFont()->setSize(9)->setBold(true);
  1130. $objPHPExcel->getActiveSheet()->getStyle('A1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1131. $objPHPExcel->getActiveSheet()->getStyle('B1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1132. $objPHPExcel->getActiveSheet()->getStyle('C1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1133. $objPHPExcel->getActiveSheet()->getStyle('D1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1134. $baseRow = 2;
  1135. foreach ($list as $key => $custom) {
  1136. $i = $baseRow + $key;
  1137. $objPHPExcel->getActiveSheet()->setCellValue('A' . $i, $custom['name']);
  1138. $objPHPExcel->getActiveSheet()->setCellValue('B' . $i, $custom['income']);
  1139. $objPHPExcel->getActiveSheet()->setCellValue('C' . $i, $custom['inNum']);
  1140. $objPHPExcel->getActiveSheet()->setCellValue('D' . $i, $custom['expend']);
  1141. $objPHPExcel->getActiveSheet()->setCellValue('E' . $i, $custom['outNum']);
  1142. $objPHPExcel->getActiveSheet()->setCellValue('F' . $i, $custom['profit']);
  1143. //居左
  1144. $objPHPExcel->getActiveSheet()->getStyle('A' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1145. $objPHPExcel->getActiveSheet()->getStyle('B' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1146. $objPHPExcel->getActiveSheet()->getStyle('C' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1147. $objPHPExcel->getActiveSheet()->getStyle('D' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1148. $objPHPExcel->getActiveSheet()->getStyle('E' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1149. $objPHPExcel->getActiveSheet()->getStyle('F' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1150. }
  1151. $fileName = '收支花材-' . date("m-d");
  1152. $objPHPExcel->getActiveSheet()->setTitle($fileName);
  1153. $objPHPExcel->setActiveSheetIndex(0);
  1154. $dir = './priceTable/' . $mainId;
  1155. if (file_exists($dir) == false) {
  1156. mkdir($dir, 0777, true);
  1157. }
  1158. $date = $fileName;
  1159. $file = $date . '.xls';
  1160. $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
  1161. if (file_exists($dir . '/' . $file)) {
  1162. unlink($dir . '/' . $file);
  1163. }
  1164. $objWriter->save($dir . '/' . $file);
  1165. $fileUrl = Yii::$app->params['ghsHost'] . '/priceTable/' . $mainId . '/' . $file;
  1166. util::success(['file' => $fileUrl, 'shortFile' => $file]);
  1167. }
  1168. public static function exportIncomeClass($list, $mainId)
  1169. {
  1170. $phpExcelFile = Yii::getAlias("@vendor/phpoffice/phpexcel/");
  1171. require_once($phpExcelFile . 'Classes/PHPExcel.php');
  1172. $objPHPExcel = new \PHPExcel();
  1173. $objPHPExcel->getProperties()->setCreator("Maarten Balliauw")
  1174. ->setLastModifiedBy("Maarten Balliauw")
  1175. ->setTitle("Office 2007 XLSX Document")
  1176. ->setSubject("Office 2007 XLSX Document")
  1177. ->setDescription("Test document for Office 2007 XLSX, generated using PHP classes.")
  1178. ->setKeywords("office 2007 openxml php")
  1179. ->setCategory("file");
  1180. $ghsTitle = '供货商';
  1181. $objPHPExcel->getActiveSheet()->getHeaderFooter()->setOddHeader(date('n月j日') . " " . $ghsTitle);
  1182. $objPHPExcel->getActiveSheet()->getPageMargins()->setTop(0.7);
  1183. $objPHPExcel->getActiveSheet()->getPageMargins()->setBottom(0.1);
  1184. $objPHPExcel->getActiveSheet()->getPageMargins()->setLeft(0.5);
  1185. $objPHPExcel->getActiveSheet()->getPageMargins()->setRight(0);
  1186. $objPHPExcel->getActiveSheet()->getPageMargins()->setHeader(0.1);
  1187. $objPHPExcel->getActiveSheet()->getPageMargins()->setFooter(0);
  1188. $objPHPExcel->getActiveSheet()->setCellValue('A1', '名称');
  1189. $objPHPExcel->getActiveSheet()->setCellValue('B1', '销售数量');
  1190. $objPHPExcel->getActiveSheet()->setCellValue('C1', '销售收入');
  1191. $objPHPExcel->getActiveSheet()->setCellValue('D1', '采购数量');
  1192. $objPHPExcel->getActiveSheet()->setCellValue('E1', '采购成本');
  1193. $objPHPExcel->getActiveSheet()->setCellValue('F1', '利润');
  1194. //设置宽度
  1195. $objPHPExcel->getActiveSheet()->getColumnDimension('A')->setWidth(20);
  1196. //加粗
  1197. $objPHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setSize(9)->setBold(true);
  1198. $objPHPExcel->getActiveSheet()->getStyle('B1')->getFont()->setSize(9)->setBold(true);
  1199. $objPHPExcel->getActiveSheet()->getStyle('C1')->getFont()->setSize(9)->setBold(true);
  1200. $objPHPExcel->getActiveSheet()->getStyle('D1')->getFont()->setSize(9)->setBold(true);
  1201. $objPHPExcel->getActiveSheet()->getStyle('E1')->getFont()->setSize(9)->setBold(true);
  1202. $objPHPExcel->getActiveSheet()->getStyle('F1')->getFont()->setSize(9)->setBold(true);
  1203. $objPHPExcel->getActiveSheet()->getStyle('A1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
  1204. $objPHPExcel->getActiveSheet()->getStyle('B1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
  1205. $objPHPExcel->getActiveSheet()->getStyle('C1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
  1206. $objPHPExcel->getActiveSheet()->getStyle('D1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
  1207. $objPHPExcel->getActiveSheet()->getStyle('E1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
  1208. $objPHPExcel->getActiveSheet()->getStyle('F1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
  1209. $objPHPExcel->getActiveSheet()->getStyle('A1')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
  1210. $objPHPExcel->getActiveSheet()->getStyle('B1')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
  1211. $objPHPExcel->getActiveSheet()->getStyle('C1')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
  1212. $objPHPExcel->getActiveSheet()->getStyle('D1')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
  1213. $objPHPExcel->getActiveSheet()->getStyle('E1')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
  1214. $objPHPExcel->getActiveSheet()->getStyle('F1')->getAlignment()->setVertical(\PHPExcel_Style_Alignment::VERTICAL_CENTER);
  1215. $baseRow = 2;
  1216. foreach ($list as $key => $custom) {
  1217. $i = $baseRow + $key;
  1218. $objPHPExcel->getActiveSheet()->setCellValue('A' . $i, $custom['className']);
  1219. $objPHPExcel->getActiveSheet()->setCellValue('B' . $i, $custom['saleNum']);
  1220. $objPHPExcel->getActiveSheet()->setCellValue('C' . $i, $custom['income']);
  1221. $objPHPExcel->getActiveSheet()->setCellValue('D' . $i, $custom['cgNum']);
  1222. $objPHPExcel->getActiveSheet()->setCellValue('E' . $i, $custom['expend']);
  1223. $objPHPExcel->getActiveSheet()->setCellValue('F' . $i, $custom['profit']);
  1224. //居左
  1225. $objPHPExcel->getActiveSheet()->getStyle('A' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
  1226. $objPHPExcel->getActiveSheet()->getStyle('B' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
  1227. $objPHPExcel->getActiveSheet()->getStyle('C' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
  1228. $objPHPExcel->getActiveSheet()->getStyle('D' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
  1229. $objPHPExcel->getActiveSheet()->getStyle('E' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
  1230. $objPHPExcel->getActiveSheet()->getStyle('F' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
  1231. }
  1232. $fileName = '收支分类-' . time();
  1233. $objPHPExcel->getActiveSheet()->setTitle($fileName);
  1234. $objPHPExcel->setActiveSheetIndex(0);
  1235. $dir = './priceTable/' . $mainId;
  1236. if (file_exists($dir) == false) {
  1237. mkdir($dir, 0777, true);
  1238. }
  1239. $date = $fileName;
  1240. $file = $date . '.xls';
  1241. $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
  1242. if (file_exists($dir . '/' . $file)) {
  1243. unlink($dir . '/' . $file);
  1244. }
  1245. $objWriter->save($dir . '/' . $file);
  1246. $fileUrl = Yii::$app->params['ghsHost'] . '/priceTable/' . $mainId . '/' . $file;
  1247. util::success(['file' => $fileUrl, 'shortFile' => $file]);
  1248. }
  1249. public static function exportItemSale($list, $mainId)
  1250. {
  1251. $phpExcelFile = Yii::getAlias("@vendor/phpoffice/phpexcel/");
  1252. require_once($phpExcelFile . 'Classes/PHPExcel.php');
  1253. $objPHPExcel = new \PHPExcel();
  1254. $objPHPExcel->getProperties()->setCreator("Maarten Balliauw")
  1255. ->setLastModifiedBy("Maarten Balliauw")
  1256. ->setTitle("Office 2007 XLSX Document")
  1257. ->setSubject("Office 2007 XLSX Document")
  1258. ->setDescription("Test document for Office 2007 XLSX, generated using PHP classes.")
  1259. ->setKeywords("office 2007 openxml php")
  1260. ->setCategory("file");
  1261. $ghsTitle = '供货商';
  1262. $objPHPExcel->getActiveSheet()->getHeaderFooter()->setOddHeader(date('n月j日') . " " . $ghsTitle);
  1263. $objPHPExcel->getActiveSheet()->getPageMargins()->setTop(0.7);
  1264. $objPHPExcel->getActiveSheet()->getPageMargins()->setBottom(0.1);
  1265. $objPHPExcel->getActiveSheet()->getPageMargins()->setLeft(0.5);
  1266. $objPHPExcel->getActiveSheet()->getPageMargins()->setRight(0);
  1267. $objPHPExcel->getActiveSheet()->getPageMargins()->setHeader(0.1);
  1268. $objPHPExcel->getActiveSheet()->getPageMargins()->setFooter(0);
  1269. $objPHPExcel->getActiveSheet()->setCellValue('A1', '名称');
  1270. $objPHPExcel->getActiveSheet()->setCellValue('B1', '总数量');
  1271. $objPHPExcel->getActiveSheet()->setCellValue('C1', '总金额');
  1272. $objPHPExcel->getActiveSheet()->setCellValue('D1', '毛利');
  1273. $objPHPExcel->getActiveSheet()->setCellValue('E1', '毛利率');
  1274. //设置宽度
  1275. $objPHPExcel->getActiveSheet()->getColumnDimension('A')->setWidth(30);
  1276. $objPHPExcel->getActiveSheet()->getColumnDimension('B')->setWidth(20);
  1277. $objPHPExcel->getActiveSheet()->getColumnDimension('C')->setWidth(20);
  1278. $objPHPExcel->getActiveSheet()->getColumnDimension('D')->setWidth(20);
  1279. $objPHPExcel->getActiveSheet()->getColumnDimension('E')->setWidth(20);
  1280. //加粗
  1281. $objPHPExcel->getActiveSheet()->getStyle('A1')->getFont()->setSize(9)->setBold(true);
  1282. $objPHPExcel->getActiveSheet()->getStyle('B1')->getFont()->setSize(9)->setBold(true);
  1283. $objPHPExcel->getActiveSheet()->getStyle('C1')->getFont()->setSize(9)->setBold(true);
  1284. $objPHPExcel->getActiveSheet()->getStyle('D1')->getFont()->setSize(9)->setBold(true);
  1285. $objPHPExcel->getActiveSheet()->getStyle('E1')->getFont()->setSize(9)->setBold(true);
  1286. $objPHPExcel->getActiveSheet()->getStyle('A1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1287. $objPHPExcel->getActiveSheet()->getStyle('B1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1288. $objPHPExcel->getActiveSheet()->getStyle('C1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1289. $objPHPExcel->getActiveSheet()->getStyle('D1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1290. $objPHPExcel->getActiveSheet()->getStyle('E1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1291. $baseRow = 2;
  1292. foreach ($list as $key => $custom) {
  1293. $i = $baseRow + $key;
  1294. $objPHPExcel->getActiveSheet()->setCellValue('A' . $i, $custom['name']);
  1295. $objPHPExcel->getActiveSheet()->setCellValue('B' . $i, $custom['num']);
  1296. $objPHPExcel->getActiveSheet()->setCellValue('C' . $i, $custom['amount']);
  1297. $objPHPExcel->getActiveSheet()->setCellValue('D' . $i, $custom['gross']);
  1298. $objPHPExcel->getActiveSheet()->setCellValue('E' . $i, $custom['mll'] . '%');
  1299. //居左
  1300. $objPHPExcel->getActiveSheet()->getStyle('A' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1301. $objPHPExcel->getActiveSheet()->getStyle('B' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1302. $objPHPExcel->getActiveSheet()->getStyle('C' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1303. $objPHPExcel->getActiveSheet()->getStyle('D' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1304. $objPHPExcel->getActiveSheet()->getStyle('E' . $i)->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
  1305. }
  1306. $fileName = '花材销量-' . date("m-d");
  1307. $objPHPExcel->getActiveSheet()->setTitle($fileName);
  1308. $objPHPExcel->setActiveSheetIndex(0);
  1309. $dir = './priceTable/' . $mainId;
  1310. if (file_exists($dir) == false) {
  1311. mkdir($dir, 0777, true);
  1312. }
  1313. $date = $fileName;
  1314. $file = $date . '.xls';
  1315. $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
  1316. if (file_exists($dir . '/' . $file)) {
  1317. unlink($dir . '/' . $file);
  1318. }
  1319. $objWriter->save($dir . '/' . $file);
  1320. $fileUrl = Yii::$app->params['ghsHost'] . '/priceTable/' . $mainId . '/' . $file;
  1321. util::success(['file' => $fileUrl, 'shortFile' => $file]);
  1322. }
  1323. public static function send($mainId)
  1324. {
  1325. $get = Yii::$app->request->get();
  1326. $where = [];
  1327. $where['mainId'] = $mainId;
  1328. $searchTime = isset($get['searchTime']) && !empty($get['searchTime']) ? $get['searchTime'] : 'today';
  1329. $startTime = $get['startTime'] ?? '';
  1330. $endTime = $get['endTime'] ?? '';
  1331. $period = dateUtil::formatTime($searchTime, $startTime, $endTime, true);
  1332. $start = $period['startTime'];
  1333. $end = $period['endTime'];
  1334. $where['time'] = ['between', [$start, $end]];
  1335. $currentStartDate = date('Y-m-d', strtotime($start));
  1336. $currentEndDate = date('Y-m-d', strtotime($end));
  1337. $currentStartTime = $currentStartDate . ' 00:00:00';
  1338. $currentEndTime = $currentEndDate . ' 23:59:59';
  1339. $s = strtotime($currentStartTime);
  1340. $e = strtotime($currentEndTime);
  1341. $p = bcsub($e, $s);
  1342. $xx = bcmul(86400, 90);
  1343. if ($p > $xx) {
  1344. util::fail('查询时间不能超过三个月,编号699');
  1345. }
  1346. $where = ['mainId' => $mainId, 'status' => ['in', [OrderClass::ORDER_STATUS_UN_SEND, OrderClass::ORDER_STATUS_SENDING, OrderClass::ORDER_STATUS_COMPLETE]]];
  1347. $where['payTime'] = ['between', [$currentStartTime, $currentEndTime]];
  1348. $ghsOrderList = OrderClass::getAllByCondition($where, null, '*');
  1349. $arr = [];
  1350. if (!empty($ghsOrderList)) {
  1351. foreach ($ghsOrderList as $ghsOrder) {
  1352. $book = $ghsOrder['book'] ?? 0;
  1353. $status = $ghsOrder['status'] ?? 0;
  1354. if ($book == 1 && $status == 2) {
  1355. //预订单待发货的不算收入
  1356. continue;
  1357. }
  1358. if ($status == 0 || $status == 5) {
  1359. continue;
  1360. }
  1361. $orderSn = $ghsOrder['orderSn'] ?? '';
  1362. $actPrice = $ghsOrder['actPrice'] ?? 0;
  1363. if ($actPrice <= 0) {
  1364. continue;
  1365. }
  1366. $sendStaffId = $ghsOrder['sendStaffId'] ?? 0;
  1367. $sendStaffName = isset($ghsOrder['sendStaffName']) && !empty($ghsOrder['sendStaffName']) ? $ghsOrder['sendStaffName'] : '未记名';
  1368. if (isset($arr[$sendStaffId])) {
  1369. $arr[$sendStaffId]['orderNum'] = bcadd($arr[$sendStaffId]['orderNum'], 1);
  1370. $arr[$sendStaffId]['amount'] = bcadd($arr[$sendStaffId]['amount'], $actPrice, 2);
  1371. } else {
  1372. $arr[$sendStaffId] = ['staffName' => $sendStaffName, 'orderNum' => 1, 'itemNum' => 0, 'amount' => $actPrice, 'staffId' => $sendStaffId];
  1373. }
  1374. $orderItemList = OrderItemClass::getAllByCondition(['orderSn' => $orderSn], null, '*', null, true);
  1375. if (!empty($orderItemList)) {
  1376. foreach ($orderItemList as $orderItem) {
  1377. $remainNum = NextDayRefundClass::payDayRemainNum(
  1378. $orderItem->xhNum ?? 0,
  1379. $orderItem->refundNum ?? 0,
  1380. $orderItem->nextRefundNum ?? 0
  1381. );
  1382. $arr[$sendStaffId]['itemNum'] = bcadd($arr[$sendStaffId]['itemNum'], $remainNum);
  1383. }
  1384. }
  1385. }
  1386. }
  1387. // 隔天售后:数量已用 nextRefundNum;通过日再扣(无当日配送也建负行)
  1388. self::applyNextDayAdjustToSendStaffRows(
  1389. $arr,
  1390. $mainId,
  1391. $currentStartTime,
  1392. $currentEndTime
  1393. );
  1394. if (!empty($arr)) {
  1395. $arr = array_values($arr);
  1396. }
  1397. return $arr;
  1398. }
  1399. public static function customDistStat($mainId)
  1400. {
  1401. $get = Yii::$app->request->get();
  1402. $where = [];
  1403. $where['mainId'] = $mainId;
  1404. $searchTime = !empty($get['searchTime']) ? $get['searchTime'] : 'today';
  1405. $startTime = $get['startTime'] ?? '';
  1406. $endTime = $get['endTime'] ?? '';
  1407. $period = dateUtil::formatTime($searchTime, $startTime, $endTime, true);
  1408. $start = $period['startTime'];
  1409. $end = $period['endTime'];
  1410. $where['time'] = ['between', [$start, $end]];
  1411. $currentStartDate = date('Y-m-d', strtotime($start));
  1412. $currentEndDate = date('Y-m-d', strtotime($end));
  1413. $currentStartTime = $currentStartDate . ' 00:00:00';
  1414. $currentEndTime = $currentEndDate . ' 23:59:59';
  1415. $where = ['mainId' => $mainId, 'status' => ['in', [OrderClass::ORDER_STATUS_UN_SEND, OrderClass::ORDER_STATUS_SENDING, OrderClass::ORDER_STATUS_COMPLETE]]];
  1416. $where['payTime'] = ['between', [$currentStartTime, $currentEndTime]];
  1417. $customList = CustomClass::getAllByCondition(['ownMainId' => $mainId], null, 'id,name,distId', 'id');
  1418. $distMap = DistClass::getAllByCondition(['mainId' => $mainId], null, '*', 'id');
  1419. $arr = [];
  1420. $ghsOrderList = OrderClass::getAllByCondition($where, null, '*');
  1421. $totalAmount = 0;
  1422. $totalNum = 0;
  1423. $totalProfit = 0;
  1424. $totalCost = 0;
  1425. if (!empty($ghsOrderList)) {
  1426. foreach ($ghsOrderList as $ghsOrder) {
  1427. $actPrice = $ghsOrder['actPrice'] ?? 0;
  1428. if ($actPrice <= 0) {
  1429. continue;
  1430. }
  1431. $cost = $ghsOrder['remainCost'] ?? 0;
  1432. $profit = bcsub($actPrice, $cost, 2);
  1433. $orderPrice = $ghsOrder['orderPrice'] ?? 0;
  1434. $tkPrice = $ghsOrder['tkPrice'] ?? 0;
  1435. $customId = $ghsOrder['customId'] ?? 0;
  1436. $status = $ghsOrder['status'] ?? 0;
  1437. $book = $ghsOrder['book'] ?? 0;
  1438. //扎数
  1439. $count = $ghsOrder['itemNum'] ?? 0;
  1440. if ($status == 1 || $status == 5) {
  1441. continue;
  1442. }
  1443. if ($book == 1 && $status == 2) {
  1444. continue;
  1445. }
  1446. $distId = $customList[$customId]['distId'] ?? 0;
  1447. $distName = isset($distMap[$distId]) ? $distMap[$distId]['name'] : '未划片区';
  1448. $totalNum++;
  1449. $totalAmount = bcadd($totalAmount, $actPrice, 2);
  1450. $totalProfit = bcadd($totalProfit, $profit, 2);
  1451. $totalCost = bcadd($totalCost, $cost, 2);
  1452. if (isset($arr[$distId])) {
  1453. $arr[$distId]['num']++;
  1454. $arr[$distId]['amount'] = bcadd($arr[$distId]['amount'], $actPrice, 2);
  1455. $arr[$distId]['orderPrice'] = bcadd($arr[$distId]['orderPrice'], $orderPrice, 2);
  1456. $arr[$distId]['count'] = bcadd($arr[$distId]['count'], $count, 2);
  1457. $arr[$distId]['tkPrice'] = bcadd($arr[$distId]['tkPrice'], $tkPrice, 2);
  1458. $arr[$distId]['cost'] = bcadd($arr[$distId]['cost'], $cost, 2);
  1459. $arr[$distId]['profit'] = bcadd($arr[$distId]['profit'], $profit, 2);
  1460. } else {
  1461. $arr[$distId] = [
  1462. 'distId' => $distId,
  1463. 'distName' => $distName,
  1464. 'num' => 1,
  1465. 'count' => $count,
  1466. 'amount' => $actPrice,
  1467. 'levelName' => '',
  1468. 'orderPrice' => $orderPrice,
  1469. 'tkPrice' => $tkPrice,
  1470. 'cost' => $cost,
  1471. 'profit' => $profit,
  1472. ];
  1473. }
  1474. }
  1475. }
  1476. // 隔天售后按客户归到片区扣金额/扎数;无当日开单的片区也建负行
  1477. $fwdMap = NextDayRefundClass::sumAmountGroupByCustom($mainId, $currentStartTime, $currentEndTime);
  1478. $qtyMap = NextDayRefundClass::sumItemQtyByCustom($mainId, $currentStartTime, $currentEndTime);
  1479. $cidKeys = array_unique(array_merge(array_keys($fwdMap), array_keys($qtyMap)));
  1480. foreach ($cidKeys as $cid) {
  1481. $amt = $fwdMap[$cid] ?? '0';
  1482. $qty = $qtyMap[$cid] ?? '0';
  1483. if (bccomp((string)$amt, '0', 2) == 0 && bccomp((string)$qty, '0', 2) == 0) {
  1484. continue;
  1485. }
  1486. $distId = $customList[$cid]['distId'] ?? 0;
  1487. if (!isset($arr[$distId])) {
  1488. $arr[$distId] = [
  1489. 'distId' => $distId,
  1490. 'distName' => isset($distMap[$distId]) ? $distMap[$distId]['name'] : '未划片区',
  1491. 'num' => 0,
  1492. 'count' => '0.00',
  1493. 'amount' => '0.00',
  1494. 'levelName' => '',
  1495. 'orderPrice' => 0,
  1496. 'tkPrice' => 0,
  1497. 'cost' => 0,
  1498. 'profit' => '0.00',
  1499. ];
  1500. }
  1501. $arr[$distId]['amount'] = bcsub((string)$arr[$distId]['amount'], (string)$amt, 2);
  1502. $arr[$distId]['profit'] = bcsub((string)$arr[$distId]['profit'], (string)$amt, 2);
  1503. $arr[$distId]['count'] = bcsub((string)($arr[$distId]['count'] ?? 0), (string)$qty, 2);
  1504. $totalAmount = bcsub((string)$totalAmount, (string)$amt, 2);
  1505. $totalProfit = bcsub((string)$totalProfit, (string)$amt, 2);
  1506. }
  1507. if (!empty($arr)) {
  1508. $arr = arrayUtil::arraySort($arr, 'profit');
  1509. }
  1510. $totalAmount = floatval($totalAmount);
  1511. return ['list' => $arr, 'totalAmount' => $totalAmount, 'totalNum' => $totalNum, 'totalCost' => $totalCost, 'totalProfit' => $totalProfit];
  1512. }
  1513. /**
  1514. * 花材收支明细:支付日已用 nextRefundNum;此处按通过日扣退货数量/金额,并返回隔天仅退款合计。
  1515. *
  1516. * @param array $arr 产品收支行(引用修改 income/inNum)
  1517. * @param array $tbSaleIncome 归属成本花材销售明细(引用同步加减)
  1518. * @param array $productList 花材字典
  1519. * @param int $mainId
  1520. * @param string $startTime
  1521. * @param string $endTime
  1522. * @return string 通过日隔天「仅退款」合计,需加到 onlyRefund
  1523. */
  1524. private static function applyNextDayAdjustToProductIncomeRows(
  1525. &$arr,
  1526. &$tbSaleIncome,
  1527. $productList,
  1528. $mainId,
  1529. $startTime,
  1530. $endTime
  1531. ) {
  1532. $applyDelta = function ($pidMap, $sign) use (&$arr, &$tbSaleIncome, $productList) {
  1533. foreach ($pidMap as $pid => $row) {
  1534. $deltaNum = bcmul((string)($row['num'] ?? '0'), (string)$sign, 2);
  1535. $deltaAmt = bcmul((string)($row['amount'] ?? '0'), (string)$sign, 2);
  1536. if (bccomp($deltaAmt, '0', 2) == 0 && bccomp($deltaNum, '0', 2) == 0) {
  1537. continue;
  1538. }
  1539. // 通过日扣减:当日无该花材开单也建负行(收入/数量可为负)
  1540. if (!isset($arr[$pid])) {
  1541. $arr[$pid] = [
  1542. 'name' => $productList[$pid]['name'] ?? '已删除',
  1543. 'id' => $pid,
  1544. 'expend' => 0,
  1545. 'outNum' => 0,
  1546. 'inNum' => '0.00',
  1547. 'income' => '0.00',
  1548. ];
  1549. }
  1550. $arr[$pid]['income'] = bcadd((string)($arr[$pid]['income'] ?? 0), $deltaAmt, 2);
  1551. $arr[$pid]['inNum'] = bcadd((string)($arr[$pid]['inNum'] ?? 0), $deltaNum, 2);
  1552. if (isset($tbSaleIncome[$pid])) {
  1553. $tbSaleIncome[$pid]['price'] = bcadd((string)($tbSaleIncome[$pid]['price'] ?? 0), $deltaAmt, 2);
  1554. $tbSaleIncome[$pid]['num'] = bcadd((string)($tbSaleIncome[$pid]['num'] ?? 0), $deltaNum, 2);
  1555. }
  1556. }
  1557. };
  1558. // 通过日:扣退货数量+金额
  1559. $applyDelta(
  1560. NextDayRefundClass::sumItemByProduct($mainId, $startTime, $endTime),
  1561. -1
  1562. );
  1563. return NextDayRefundClass::sumMoneyOnlyAmountByMainAndTime($mainId, $startTime, $endTime);
  1564. }
  1565. /**
  1566. * 配送业绩:支付日数量已用 nextRefundNum;通过日再扣数量/金额(仅退款只减金额)。
  1567. * 无当日配送单的配送员也会建负行业绩行。
  1568. *
  1569. * @param array $arr sendStaffId => 业绩行(引用修改 itemNum/amount)
  1570. * @param int $mainId
  1571. * @param string $startTime
  1572. * @param string $endTime
  1573. */
  1574. private static function applyNextDayAdjustToSendStaffRows(
  1575. &$arr,
  1576. $mainId,
  1577. $startTime,
  1578. $endTime
  1579. ) {
  1580. $applyDelta = function ($staffMap, $sign) use (&$arr) {
  1581. foreach ($staffMap as $sid => $row) {
  1582. $deltaNum = bcmul((string)($row['num'] ?? '0'), (string)$sign, 2);
  1583. $deltaAmt = bcmul((string)($row['amount'] ?? '0'), (string)$sign, 2);
  1584. if (bccomp($deltaAmt, '0', 2) == 0 && bccomp($deltaNum, '0', 2) == 0) {
  1585. continue;
  1586. }
  1587. if (!isset($arr[$sid])) {
  1588. $arr[$sid] = [
  1589. 'staffName' => '未记名',
  1590. 'orderNum' => 0,
  1591. 'itemNum' => '0.00',
  1592. 'amount' => '0.00',
  1593. 'staffId' => $sid,
  1594. ];
  1595. }
  1596. $arr[$sid]['itemNum'] = bcadd((string)($arr[$sid]['itemNum'] ?? 0), $deltaNum, 2);
  1597. $arr[$sid]['amount'] = bcadd((string)($arr[$sid]['amount'] ?? 0), $deltaAmt, 2);
  1598. }
  1599. };
  1600. $applyDelta(
  1601. NextDayRefundClass::sumItemBySendStaff($mainId, $startTime, $endTime),
  1602. -1
  1603. );
  1604. // 仅退款只减金额
  1605. $applyDelta(
  1606. NextDayRefundClass::sumMoneyOnlyAmountBySendStaff($mainId, $startTime, $endTime),
  1607. -1
  1608. );
  1609. }
  1610. }