StatSaleClass.php 95 KB

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