ProfitService.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. <?php
  2. namespace app\api\service;
  3. use app\admin\model\Admin;
  4. use app\admin\model\profit\Bill;
  5. use app\api\model\Channel;
  6. use app\api\model\massager\Massager;
  7. use app\api\model\massager\Wallet;
  8. use app\api\model\massager\Work;
  9. use app\api\model\Store;
  10. use app\api\model\User;
  11. use redis\RedLock;
  12. use think\Db;
  13. use think\Exception;
  14. class ProfitService extends BaseService
  15. {
  16. private $adminModel;
  17. private $storeModel;
  18. private $massagerModel;
  19. private $pBillModel;
  20. private $mBillModel;
  21. private $mWalletModel;
  22. private $userModel;
  23. private $uBillModel;
  24. private $uWalletModel;
  25. public function __construct()
  26. {
  27. $this->adminModel = new Admin();
  28. $this->storeModel = new Store();
  29. $this->massagerModel = new Massager();
  30. $this->pBillModel = new Bill();
  31. $this->mBillModel = new \app\api\model\massager\Bill();
  32. $this->mWalletModel = new Wallet();
  33. $this->userModel = new User();
  34. $this->uBillModel = new \app\api\model\user\Bill();
  35. $this->uWalletModel = new \app\api\model\user\Wallet();
  36. }
  37. public function profit($order, $user, $unusual = false)
  38. {
  39. $platform = $this->adminModel->where("id", "=", 1)->find();
  40. if (!$platform)
  41. return $this->fail("Admin不存在!");
  42. $massager = $this->massagerModel->getMassager($order->massager_id);
  43. if ($order["massager_id"] > 0) {
  44. if (!$massager)
  45. return $this->fail("助教信息不存在!");
  46. }
  47. $agency = $this->adminModel->findAgency($order->city_code);
  48. $redLock = new RedLock();
  49. $agencyLock = false;
  50. $sLock = false;
  51. $mLock = false;
  52. if ($agency) {
  53. $agencyLock = $redLock->lock(Admin::AgencyKey($agency->id));
  54. if (!is_array($agencyLock))
  55. return $this->fail("请稍后再试!");
  56. }
  57. // 平台抽成比例
  58. $platform_rate = config("site.platform_profit_rate") ?? 6;
  59. // 代理商抽成比例
  60. $agency_rate = 0;
  61. // 渠道商分佣
  62. $parent_direct_invite_rate = 0; // 1级
  63. $store = $this->storeModel->findById($order->store_id ?? -1);
  64. if ($order["store_id"] > 0) { // 球房分润标准
  65. if (!$store)
  66. return $this->fail("球房信息不存在!");
  67. $sLock = $redLock->lock(Store::SWKey($order->store_id));
  68. if (!is_array($sLock))
  69. return $this->fail("请稍后再试!");
  70. $self_rate = 100 - $store["platform_profit_rate"] - $store["agency_profit_rate"];
  71. if ($agency) {
  72. $agency_rate = $store["agency_profit_rate"];
  73. } else {
  74. // 如果代理商不存在 则剩余部分 全部归于平台;
  75. $platform_rate = $store["agency_profit_rate"] + $store["platform_profit_rate"];
  76. }
  77. } else { // 线上分润标准
  78. $mLock = $redLock->lock(\app\api\model\massager\Wallet::MWKey($order->massager_id));
  79. if (!is_array($mLock))
  80. return $this->fail("请稍后再试!");
  81. // 本人比例
  82. $self_rate = (new MassagerService())->getProfitRate($massager["id"], $massager["city_code"], null, null, date("Y-m-d", $order["createtime"]));
  83. if ($agency) {
  84. $agency_rate = 100 - ($platform_rate + $self_rate);
  85. } else {
  86. // 如果代理商不存在 则剩余部分 全部归于平台;
  87. $platform_rate = 100 - $self_rate;
  88. }
  89. }
  90. $parent = null;
  91. $parent_lock = null;
  92. $parent_wallet = null;
  93. if (1 == config("site.invite_grant_switch") && !$unusual && $massager["parent_id"] > 0) { // 渠道奖励发放开启
  94. $parent = $this->massagerModel->get($massager["parent_id"]);
  95. if ($parent) {
  96. $parent_lock = $redLock->lock(Wallet::MWKey($parent->id));
  97. $parent_wallet = $this->mWalletModel->getWallet($parent->id);
  98. $parent_direct_invite_rate = config("site.massager_direct_invite_rate");
  99. }
  100. }
  101. $invite_store = null;
  102. $store_direct_invite_rate = 0;
  103. if (!$unusual && $user["invite_store_id"] > 0) {// 渠道奖励发放开启
  104. $invite_store = $this->storeModel->get($user["invite_store_id"]);
  105. $store_direct_invite_rate = config("site.store_direct_invite_rate");
  106. }
  107. if (fixed2Float(($platform_rate + $agency_rate + $self_rate)) != 100) {
  108. return $this->fail("比例计算错误!");
  109. }
  110. $pLock = $redLock->lock(Admin::PlatformKey());
  111. if (!is_array($pLock))
  112. return $this->fail("请稍后再试!");
  113. $mWallet = $this->mWalletModel->getWallet($order->massager_id);
  114. $locks = [$pLock, $agencyLock, $sLock, $mLock, $parent_lock];
  115. $trip_amount = $order->trip_amount;
  116. // 实际支付金额 - 出行费 = 订单分润金额
  117. $total_profit_amount = $order->total_real_amount - $trip_amount;
  118. if ($unusual && $order["is_refund_trip"] == 1) {
  119. $trip_amount = 0;
  120. }
  121. if ($unusual) { // 管理员终止
  122. $total_profit_amount = $order->total_real_amount - $order->refund_amount - $trip_amount;
  123. }
  124. if ($total_profit_amount <= 0)
  125. return $this->fail("分润金额小于0");
  126. $p_profit_amount = fixed2Float($total_profit_amount * ($platform_rate / 100));
  127. $a_profit_amount = $agency_rate > 0 ? fixed2Float($total_profit_amount * ($agency_rate / 100)) : 0;
  128. $self_profit_amount = fixed2Float($total_profit_amount * ($self_rate / 100));
  129. // 助教直推助教奖励(%)
  130. $parent_profit_amount = $parent_direct_invite_rate > 0 ? fixed2Float($total_profit_amount * ($parent_direct_invite_rate / 100)) : 0;
  131. $total_parent_amount = $parent_profit_amount;
  132. // 球房直推用户奖励(%)
  133. $invite_store_profit_amount = $store_direct_invite_rate > 0 ? fixed2Float($total_profit_amount * ($store_direct_invite_rate / 100)) : 0;
  134. Db::startTrans();
  135. try {
  136. $profit_bills = [
  137. [
  138. "identity_type" => \E_IDENTITY_TYPE::Platform,
  139. "target_id" => 1,
  140. "target_name" => "平台",
  141. "change_type" => \E_PROFIT_BILL_CHANGE_TYPE::Profit,
  142. "order_no" => $order->no,
  143. "total_amount" => $total_profit_amount,
  144. "rate" => $platform_rate,
  145. "change" => $p_profit_amount,
  146. "before" => $platform->profit_amount,
  147. "after" => fixed2Float($platform->profit_amount + $p_profit_amount),
  148. "createtime" => time(),
  149. "city_code" => $order->city_code
  150. ]
  151. ];
  152. if ($order->store_id > 0) { // 门店
  153. $after = fixed2Float($store->profit_amount + $self_profit_amount);
  154. $profit_bills[] = [
  155. "identity_type" => \E_IDENTITY_TYPE::Store,
  156. "target_id" => $store->id,
  157. "target_name" => $store->name,
  158. "change_type" => \E_PROFIT_BILL_CHANGE_TYPE::Profit,
  159. "order_no" => $order->no,
  160. "total_amount" => $total_profit_amount,
  161. "rate" => $self_rate,
  162. "change" => $self_profit_amount,
  163. "before" => $store->profit_amount,
  164. "after" => $after,
  165. "createtime" => time(),
  166. "city_code" => $order->city_code
  167. ];
  168. $this->storeModel->where("id", $store->id)->setInc("profit_amount", $self_profit_amount);
  169. } else { // 助教
  170. $after = fixed2Float($mWallet->profit_amount + $self_profit_amount);
  171. $profit_bills[] = [
  172. "identity_type" => \E_IDENTITY_TYPE::Massager,
  173. "target_id" => $massager->id,
  174. "target_name" => $massager->name,
  175. "change_type" => \E_PROFIT_BILL_CHANGE_TYPE::Profit,
  176. "order_no" => $order->no,
  177. "total_amount" => $total_profit_amount,
  178. "rate" => $self_rate,
  179. "change" => $self_profit_amount - $total_parent_amount - $invite_store_profit_amount,
  180. "before" => $mWallet->profit_amount,
  181. "after" => $after,
  182. "createtime" => time(),
  183. "city_code" => $order->city_code
  184. ];
  185. $m_bills = [
  186. [
  187. "massager_id" => $massager->id,
  188. "currency_type" => \E_USER_BILL_CURRENCY_TYPE::Money,
  189. "change_type" => \E_M_BILL_CHANGE_TYPE::Profit,
  190. "change" => $self_profit_amount,
  191. "before" => $mWallet->profit_amount,
  192. "after" => $after,
  193. "reason" => "服务费用",
  194. "relation_no" => $order->no,
  195. "createtime" => time()
  196. ]
  197. ];
  198. if ($trip_amount > 0) {
  199. $m_bills[] = [
  200. "massager_id" => $massager->id,
  201. "currency_type" => \E_USER_BILL_CURRENCY_TYPE::Money,
  202. "change_type" => \E_M_BILL_CHANGE_TYPE::Travel,
  203. "change" => $trip_amount,
  204. "before" => $after,
  205. "after" => $after + $trip_amount,
  206. "reason" => "出行费用",
  207. "relation_no" => $order->no,
  208. "createtime" => time()
  209. ];
  210. }
  211. if ($total_parent_amount > 0) {
  212. $m_bills[] = [
  213. "massager_id" => $massager->id,
  214. "currency_type" => \E_USER_BILL_CURRENCY_TYPE::Money,
  215. "change_type" => \E_M_BILL_CHANGE_TYPE::ChannelExpend,
  216. "change" => -$total_parent_amount,
  217. "before" => ($after + $trip_amount),
  218. "after" => ($after + $trip_amount) - $total_parent_amount,
  219. "reason" => "技师渠道抽佣",
  220. "relation_no" => $order->no,
  221. "createtime" => time()
  222. ];
  223. }
  224. if ($invite_store_profit_amount > 0) {
  225. $m_bills[] = [
  226. "massager_id" => $massager->id,
  227. "currency_type" => \E_USER_BILL_CURRENCY_TYPE::Money,
  228. "change_type" => \E_M_BILL_CHANGE_TYPE::ChannelExpend,
  229. "change" => -$invite_store_profit_amount,
  230. "before" => ($after + $trip_amount),
  231. "after" => ($after + $trip_amount) - $total_parent_amount - $invite_store_profit_amount,
  232. "reason" => "门店渠道抽佣",
  233. "relation_no" => $order->no,
  234. "createtime" => time()
  235. ];
  236. }
  237. $this->mWalletModel->where("id", $mWallet->id)->setInc(
  238. "profit_amount",
  239. ($self_profit_amount + $trip_amount - $total_parent_amount - $invite_store_profit_amount)
  240. );
  241. $this->mBillModel->insertAll($m_bills);
  242. }
  243. if ($agency && $a_profit_amount > 0) {
  244. $profit_bills[] = [
  245. "identity_type" => \E_IDENTITY_TYPE::Agency,
  246. "target_id" => $agency->id,
  247. "target_name" => $agency->nickname,
  248. "change_type" => \E_PROFIT_BILL_CHANGE_TYPE::Profit,
  249. "order_no" => $order->no,
  250. "total_amount" => $total_profit_amount,
  251. "rate" => $agency_rate,
  252. "change" => $a_profit_amount,
  253. "before" => $agency->profit_amount,
  254. "after" => fixed2Float($agency->profit_amount + $a_profit_amount),
  255. "createtime" => time(),
  256. "city_code" => $order->city_code
  257. ];
  258. $this->adminModel->where("id", $agency->id)->setInc("profit_amount", $a_profit_amount);
  259. }
  260. $this->adminModel->where("id", 1)->setInc("profit_amount", $p_profit_amount);
  261. if ($parent && $total_parent_amount > 0) { // 技师邀请技师存在!
  262. $profit_bills[] = [
  263. "identity_type" => \E_IDENTITY_TYPE::Massager,
  264. "target_id" => $parent->id,
  265. "target_name" => $parent->name,
  266. "change_type" => \E_PROFIT_BILL_CHANGE_TYPE::ChannelIncome,
  267. "order_no" => $order->no,
  268. "total_amount" => $total_profit_amount,
  269. "rate" => $parent_direct_invite_rate,
  270. "change" => $parent_profit_amount,
  271. "before" => fixed2Float($parent_wallet->profit_amount),
  272. "after" => fixed2Float($parent_wallet->profit_amount + $parent_profit_amount),
  273. "createtime" => time(),
  274. "city_code" => $order->city_code
  275. ];
  276. $this->mBillModel->save([
  277. "massager_id" => $parent->id,
  278. "currency_type" => \E_USER_BILL_CURRENCY_TYPE::Money,
  279. "change_type" => \E_M_BILL_CHANGE_TYPE::ChannelIncome,
  280. "change" => $total_parent_amount,
  281. "before" => $parent_wallet["profit_amount"],
  282. "after" => $parent_wallet["profit_amount"] + $total_parent_amount,
  283. "reason" => "渠道抽佣",
  284. "relation_no" => $order->no,
  285. "createtime" => time()
  286. ]);
  287. if ($parent_wallet) {
  288. $this->mWalletModel->where("id", $parent_wallet->id)->setInc("profit_amount", $parent_profit_amount);
  289. }
  290. }
  291. if ($invite_store_profit_amount > 0) { // 门店邀请技师存在 - 渠道抽佣
  292. if ($invite_store) {
  293. $profit_bills[] = [
  294. "identity_type" => \E_IDENTITY_TYPE::Store,
  295. "target_id" => $invite_store->id,
  296. "target_name" => $invite_store->name,
  297. "change_type" => \E_PROFIT_BILL_CHANGE_TYPE::ChannelIncome,
  298. "order_no" => $order->no,
  299. "total_amount" => $total_profit_amount,
  300. "rate" => $store_direct_invite_rate,
  301. "change" => $invite_store_profit_amount,
  302. "before" => fixed2Float($invite_store->profit_amount),
  303. "after" => fixed2Float($invite_store->profit_amount + $invite_store_profit_amount),
  304. "createtime" => time(),
  305. "city_code" => $order->city_code
  306. ];
  307. $this->storeModel->where("id", $invite_store->id)->setInc("profit_amount", $invite_store_profit_amount);
  308. }
  309. }
  310. $this->pBillModel->insertAll($profit_bills);
  311. Db::commit();
  312. return $this->ok(true);
  313. } catch (Exception $e) {
  314. Db::rollback();
  315. return $this->fail($e->getMessage());
  316. } finally {
  317. foreach ($locks as $lock) {
  318. if (is_array($lock))
  319. $redLock->unlock($lock);
  320. }
  321. }
  322. }
  323. }