BookSettlement.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. <?php
  2. namespace Modules\ContentManage\Services\CpManage;
  3. use Illuminate\Support\Facades\DB;
  4. use Modules\Common\Support\Trace\CustomizeLogger;
  5. use Modules\Common\Support\Trace\TraceContext;
  6. class BookSettlement
  7. {
  8. private $settlementResult = [];
  9. private $bid;
  10. // 初始的结算模式信息
  11. private $initialSettlementModeInfo = null;
  12. private $month;
  13. private $lastMonthLastDate;
  14. private $currentMonthLastDate;
  15. private $currentMonthFirstDate;
  16. private $settlementModeInfos = null;
  17. private $finalAmounts = null;
  18. private $logger;
  19. /**
  20. * @var TraceContext
  21. */
  22. public $traceContext;
  23. public function __construct($bid, $month)
  24. {
  25. $this->bid = $bid;
  26. $this->month = $month;
  27. $this->currentMonthFirstDate = $this->month . '-01';
  28. $this->lastMonthLastDate = date_sub(date_create($this->currentMonthFirstDate),
  29. date_interval_create_from_date_string('1 day'))->format('Y-m-d');
  30. $this->currentMonthLastDate = date_sub(date_add(date_create($this->month),
  31. date_interval_create_from_date_string('1 month')),
  32. date_interval_create_from_date_string('1 day'))->format('Y-m-d');
  33. $this->logger = CustomizeLogger::getLogger('bookMonthSettlement', 'debug');
  34. $this->traceContext = app(TraceContext::class);
  35. }
  36. private function initSettlementModeInfo() {
  37. $record = DB::table('book_settlement_mode_history')
  38. ->where(['bid' => $this->bid, 'is_enabled' => 1])
  39. ->where('effective_date', '<', $this->currentMonthFirstDate)
  40. ->orderBy('id', 'desc')
  41. ->first();
  42. if(!$record) {
  43. $bookInfo = DB::table('books')
  44. ->where(['id' => $this->bid])
  45. ->select('id', 'settlement_type', 'bottomline')
  46. ->first();
  47. $modeInfo = [
  48. 'settlement_mode' => $bookInfo->settlement_type,
  49. 'bottomline' => $bookInfo->bottomline,
  50. 'effective_date' => '2000-01-01',
  51. 'total_amount' => 0,
  52. 'change_reason' => 'manual',
  53. ];
  54. } else {
  55. $modeInfo = [
  56. 'settlement_mode' => $record->settlement_mode,
  57. 'bottomline' => $record->bottomline,
  58. 'effective_date' => $record->effective_date,
  59. 'total_amount' => $record->total_amount,
  60. 'change_reason' => $record->change_reason,
  61. ];
  62. }
  63. if('bottomline' == $modeInfo['settlement_mode']) {
  64. if('manual' == $modeInfo['change_reason']) {
  65. $modeInfo['total_amount'] = $this->getBookTotalAmount($modeInfo['effective_date']);
  66. }
  67. if($modeInfo['total_amount'] >= $modeInfo['bottomline']) {
  68. $modeInfo['settlement_mode'] = 'out_bottomline';
  69. }
  70. }
  71. $this->logger->debug('初始结算状态', [
  72. 'traceInfo' => $this->traceContext->getTraceInfo(),
  73. 'modeInfo' => $modeInfo]);
  74. return $modeInfo;
  75. }
  76. private function getBookTotalAmount($effectiveDate) {
  77. return DB::table('cp_subscribe_statistic_data')
  78. ->where([
  79. ['settlement_date', '>=', $effectiveDate],
  80. ['settlement_date', '<=', $this->lastMonthLastDate],
  81. ['bid' , '=', $this->bid],
  82. ])->sum('yesterday_final_amount');
  83. }
  84. private function getInitialSettlementModeInfo(){
  85. if(is_null($this->initialSettlementModeInfo)) {
  86. $this->initialSettlementModeInfo = $this->initSettlementModeInfo();
  87. }
  88. return $this->initialSettlementModeInfo;
  89. }
  90. /**
  91. * 获取本月可用结算模式
  92. * @return null
  93. */
  94. private function getSettlementModes() {
  95. if(is_null($this->settlementModeInfos)) {
  96. $initSettlementMode = $this->getInitialSettlementModeInfo();
  97. $this->settlementModeInfos[$initSettlementMode['effective_date']] = $initSettlementMode;
  98. $historyList = DB::table('book_settlement_mode_history')
  99. ->whereBetween('effective_date', [$this->currentMonthFirstDate, $this->currentMonthLastDate])
  100. ->where(['is_enabled' => 1, 'bid' => $this->bid])
  101. ->orderBy('id', 'asc')
  102. ->get();
  103. foreach ($historyList as $history) {
  104. $this->settlementModeInfos[$history->effective_date] = [
  105. 'settlement_mode' => $history->settlement_mode,
  106. 'bottomline' => $history->bottomline,
  107. 'effective_date' => $history->effective_date,
  108. 'total_amount' => $history->total_amount
  109. ];
  110. }
  111. }
  112. return $this->settlementModeInfos;
  113. }
  114. /**
  115. * 获取本月每日原始应结算金额明细
  116. * @return \Illuminate\Support\Collection
  117. */
  118. private function getFinalAmounts() {
  119. if (is_null($this->finalAmounts)) {
  120. $this->finalAmounts = DB::table('cp_subscribe_statistic_data')
  121. ->whereBetween('settlement_date', [$this->currentMonthFirstDate, $this->currentMonthLastDate])
  122. ->select('yesterday_final_amount', 'settlement_date', 'bid')
  123. ->where(['bid' => $this->bid])
  124. ->get()->keyBy('settlement_date');
  125. }
  126. return $this->finalAmounts;
  127. }
  128. /**
  129. * 获取 {month} 中各天的应结算金额
  130. * @return array
  131. * <pre>
  132. * [
  133. * "2023-03-01"=> 2.5,
  134. * "2023-03-02"=> 2.5,
  135. * ...
  136. * "2023-03-30"=> 2.5,
  137. * "2023-03-31"=> 2.5,
  138. * ]
  139. * </pre>
  140. */
  141. public function detail() {
  142. $this->logger->debug('开始处理书籍', [
  143. 'traceInfo' => $this->traceContext->getTraceInfo(),
  144. 'bid' => $this->bid, 'month' => $this->month,
  145. ]);
  146. $date = $this->currentMonthFirstDate;
  147. $settlementModes = $this->getSettlementModes();
  148. $this->logger->debug('结算状态集合', ['traceInfo' => $this->traceContext->getTraceInfo(),
  149. 'settlementModeInfos' => $settlementModes]);
  150. $finalAmounts = $this->getFinalAmounts();
  151. $this->logger->debug('原始应结算金额', ['traceInfo' => $this->traceContext->getTraceInfo(),
  152. 'sourceFinalAmounts' => $finalAmounts->toArray()]);
  153. while ($date <= $this->currentMonthLastDate) {
  154. $this->logger->debug('开始处理日期:'. $date, ['traceInfo' => $this->traceContext->getTraceInfo(),
  155. 'date' => $date]);
  156. $nextDate = date_add(date_create($date), date_interval_create_from_date_string('1 day'))
  157. ->format('Y-m-d');
  158. if($finalAmounts->has($date)) {
  159. $currentSettlementMode = null;
  160. ksort($settlementModes);
  161. foreach ($settlementModes as $settlementMode) {
  162. if($date >= $settlementMode['effective_date']) {
  163. $currentSettlementMode = $settlementMode;
  164. }
  165. }
  166. $sourceFinalAmount = $finalAmounts->get($date)->yesterday_final_amount;
  167. $this->logger->debug('该天有原始应结算金额数据', ['traceInfo' => $this->traceContext->getTraceInfo(),
  168. 'sourceFinalAmount' => $sourceFinalAmount]);
  169. $this->logger->debug('该日期可用的结算模式', ['traceInfo' => $this->traceContext->getTraceInfo(),
  170. 'settlementMode' => $currentSettlementMode]);
  171. if('bottomline' == $currentSettlementMode['settlement_mode']) {
  172. $settlementModes[$currentSettlementMode['effective_date']]['total_amount'] += $sourceFinalAmount;
  173. if($settlementModes[$currentSettlementMode['effective_date']]['total_amount'] >
  174. $settlementModes[$currentSettlementMode['effective_date']]['bottomline']) {
  175. $this->settlementResult[$date] = $settlementModes[$currentSettlementMode['effective_date']]['total_amount'] -
  176. $settlementModes[$currentSettlementMode['effective_date']]['bottomline'];
  177. $this->logger->debug('当前原始应结算金额累计超出书籍保底金额',
  178. ['traceInfo' => $this->traceContext->getTraceInfo(),
  179. 'currentSettlementMode' => $settlementModes[$currentSettlementMode['effective_date']],
  180. 'realFinalAmount' => $this->settlementResult[$date]]);
  181. if(!key_exists($nextDate, $settlementModes)) {
  182. $this->logger->debug('下一天没有对应结算模式故可增加一个超保底结算模式,保证下一天按超保底结算',
  183. ['traceInfo' => $this->traceContext->getTraceInfo(), 'nextDate' => $nextDate]);
  184. $settlementModes[$nextDate] = [
  185. 'settlement_mode' => 'out_bottomline',
  186. 'effective_date' => $nextDate,
  187. 'total_amount' => 0,
  188. 'bottomline' => 0,
  189. ];
  190. }
  191. } else {
  192. $this->logger->debug('当前原始应结算金额没有超出书籍保底金额',
  193. ['traceInfo' => $this->traceContext->getTraceInfo(), 'realFinalAmount' => 0]);
  194. $this->settlementResult[$date] = 0;
  195. }
  196. }
  197. elseif ('buyout' == $currentSettlementMode['settlement_mode']) {
  198. $this->logger->debug('当前书籍结算模式为买断,故该天最终结算0',
  199. ['traceInfo' => $this->traceContext->getTraceInfo(), 'realFinalAmount' => 0]);
  200. $this->settlementResult[$date] = 0;
  201. }
  202. else {
  203. $this->logger->debug('其他的结算模式,应结算金额保持不变',
  204. ['traceInfo' => $this->traceContext->getTraceInfo(), 'realFinalAmount' => $sourceFinalAmount]);
  205. $this->settlementResult[$date] = $sourceFinalAmount;
  206. }
  207. } else {
  208. $this->settlementResult[$date] = 0;
  209. }
  210. $date = $nextDate;
  211. }
  212. ksort($settlementModes);
  213. $lastMonthLastDateSettlementMode = \last($settlementModes);
  214. $now = date('Y-m-d H:i:s');
  215. if('out_bottomline' == $lastMonthLastDateSettlementMode['settlement_mode']) {
  216. $this->logger->debug('入库保存本月最后一个结算模式', ['traceInfo' => $this->traceContext->getTraceInfo(),
  217. 'lastMonthLastDateSettlementMode' => $lastMonthLastDateSettlementMode]);
  218. DB::table('book_settlement_mode_history')
  219. ->insert([
  220. 'bid' => $this->bid,
  221. 'effective_date' => $this->currentMonthLastDate,
  222. 'settlement_mode' => $lastMonthLastDateSettlementMode['settlement_mode'],
  223. 'bottomline' => $lastMonthLastDateSettlementMode['bottomline'],
  224. 'total_amount' => $lastMonthLastDateSettlementMode['total_amount'],
  225. 'change_reason' => 'auto',
  226. 'created_at' => $now,
  227. 'updated_at' => $now
  228. ]);
  229. }
  230. return $this->settlementResult;
  231. }
  232. }