Payment.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2017~2024 https://www.yiovo.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
  8. // +----------------------------------------------------------------------
  9. // | Author: 萤火科技 <admin@yiovo.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types=1);
  12. namespace app\common\model;
  13. use cores\BaseModel;
  14. use cores\exception\BaseException;
  15. use think\facade\Cache;
  16. use think\model\relation\BelongsTo;
  17. use app\common\library\helper;
  18. use app\common\model\PaymentTemplate as PaymentTemplateModel;
  19. use app\common\enum\Client as ClientEnum;
  20. use app\common\enum\payment\Method as PaymentMethodEnum;
  21. /**
  22. * 模型类:支付方式记录
  23. * Class Payment
  24. * @package app\common\model
  25. */
  26. class Payment extends BaseModel
  27. {
  28. // 定义表名
  29. protected $name = 'payment';
  30. // 定义主键
  31. protected $pk = 'payment_id';
  32. /**
  33. * 关联支付模板记录表
  34. * @return BelongsTo
  35. */
  36. public function template(): BelongsTo
  37. {
  38. return $this->belongsTo('PaymentTemplate');
  39. }
  40. /**
  41. * 获取器:其他选项
  42. * @param $value
  43. * @return array
  44. */
  45. public function getOthersAttr($value): array
  46. {
  47. return helper::jsonDecode($value);
  48. }
  49. /**
  50. * 修改器:其他选项
  51. * @param $value
  52. * @return string
  53. */
  54. public function setOthersAttr($value): string
  55. {
  56. return helper::jsonEncode($value);
  57. }
  58. /**
  59. * 支付方式详情
  60. * @param int $paymentId
  61. * @return static|array|null
  62. */
  63. public static function detail(int $paymentId)
  64. {
  65. return self::get($paymentId);
  66. }
  67. /**
  68. * 获取支付方式配置
  69. * @throws \think\db\exception\ModelNotFoundException
  70. * @throws \think\db\exception\DbException
  71. * @throws \think\db\exception\DataNotFoundException
  72. */
  73. public static function getAll(int $storeId): array
  74. {
  75. // 实例化当前模型
  76. $model = new static;
  77. // 默认的支付方式数据
  78. $defaultData = $model->defaultData();
  79. if (!$data = Cache::get("payment_{$storeId}")) {
  80. // 获取所有支付方式
  81. $data = $model->dataByStorage($storeId, $defaultData);
  82. // 写入缓存中
  83. Cache::tag('cache')->set("payment_{$storeId}", $data);
  84. }
  85. return static::resetOptions($defaultData, $data);
  86. }
  87. /**
  88. * 获取指定客户端的支付方式
  89. * @param string $client
  90. * @param int $storeId
  91. * @return array
  92. * @throws \think\db\exception\DataNotFoundException
  93. * @throws \think\db\exception\DbException
  94. * @throws \think\db\exception\ModelNotFoundException
  95. */
  96. public static function getItem(string $client, int $storeId): array
  97. {
  98. return static::getAll($storeId)[$client];
  99. }
  100. /**
  101. * 重组缓存数据 (多维)
  102. * @param array $defaultData
  103. * @param array $data
  104. * @return array
  105. */
  106. private static function resetOptions(array $defaultData, array $data): array
  107. {
  108. $data = \resetOptions($defaultData, $data);
  109. foreach ($data as &$item) {
  110. $item['methods'] = array_values($item['methods']);
  111. }
  112. return $data;
  113. }
  114. /**
  115. * 获取所有支付方式 (从数据库中)
  116. * @param int $storeId
  117. * @param array $defaultData
  118. * @return array
  119. * @throws \think\db\exception\DataNotFoundException
  120. * @throws \think\db\exception\DbException
  121. * @throws \think\db\exception\ModelNotFoundException
  122. */
  123. private function dataByStorage(int $storeId, array $defaultData): array
  124. {
  125. // 获取数据库中所有的支付方式
  126. $list = $this->where('store_id', '=', $storeId)->select();
  127. if ($list->isEmpty()) {
  128. return [];
  129. }
  130. // 客户端标识合集
  131. $clientKeys = helper::getArrayColumn($defaultData, 'client');
  132. // 整理数据格式
  133. $data = [];
  134. $listArr = $list->toArray();
  135. foreach ($clientKeys as $client) {
  136. $listAsClient = $this->listAsClient($listArr, $client);
  137. $methods = empty($listAsClient) ? [] : $this->buildMethods($client, $listAsClient);
  138. if (!empty($methods)) {
  139. $data[$client] = ['client' => $client, 'methods' => $this->buildMethods($client, $listAsClient)];
  140. }
  141. }
  142. return $data;
  143. }
  144. /**
  145. * 格式化支付方式数据 (赋值key用于合并默认数据)
  146. * @param string $client
  147. * @param array $listAsClient
  148. * @return array
  149. */
  150. private function buildMethods(string $client, array $listAsClient): array
  151. {
  152. $methods = helper::getArrayColumns($listAsClient, [
  153. 'method', 'client', 'is_must_template', 'template_id',
  154. 'is_enable', 'is_default', 'others'
  155. ]);
  156. $data = [];
  157. foreach ($methods as $item) {
  158. if ($item['client'] === $client) {
  159. $data["$client-{$item['method']}"] = $item;
  160. }
  161. }
  162. return $data;
  163. }
  164. /**
  165. * 默认的支付方式数据
  166. * @return array[]
  167. */
  168. protected function defaultData(): array
  169. {
  170. $data = [
  171. ClientEnum::MP_WEIXIN => $this->defaultGroup(ClientEnum::MP_WEIXIN, [
  172. PaymentMethodEnum::WECHAT,
  173. PaymentMethodEnum::BALANCE,
  174. ]),
  175. ClientEnum::H5 => $this->defaultGroup(ClientEnum::H5, [
  176. PaymentMethodEnum::WECHAT,
  177. PaymentMethodEnum::ALIPAY,
  178. PaymentMethodEnum::BALANCE,
  179. ]),
  180. ClientEnum::WXOFFICIAL => $this->defaultGroup(ClientEnum::WXOFFICIAL, [
  181. // PaymentMethodEnum::WECHAT,
  182. PaymentMethodEnum::BALANCE,
  183. ]),
  184. ClientEnum::APP => $this->defaultGroup(ClientEnum::APP, [
  185. PaymentMethodEnum::WECHAT,
  186. PaymentMethodEnum::ALIPAY,
  187. PaymentMethodEnum::BALANCE,
  188. ]),
  189. ];
  190. return $data;
  191. }
  192. /**
  193. * 默认的支付客户端分组
  194. * @param string $client
  195. * @param array $designated
  196. * @return array
  197. */
  198. private function defaultGroup(string $client, array $designated): array
  199. {
  200. return [
  201. 'client' => $client,
  202. 'name' => ClientEnum::getName($client),
  203. 'desc' => '在' . ClientEnum::getName($client) . '付款时使用',
  204. 'methods' => $this->defaultMethods($client, $designated)
  205. ];
  206. }
  207. /**
  208. * 默认的methods数据
  209. * @param string $client
  210. * @param array $designated
  211. * @return array
  212. */
  213. private function defaultMethods(string $client, array $designated): array
  214. {
  215. $record = [
  216. 'key' => 1,
  217. 'method' => PaymentMethodEnum::WECHAT, // 支付方式
  218. 'is_must_template' => true, // 是否必须使用模板
  219. 'template_id' => 0, // 模板ID
  220. 'is_enable' => false, // 是否启用该支付方式
  221. 'is_default' => false, // 是否为默认支付方式
  222. 'others' => [] // 其他配置
  223. ];
  224. $defaultMethods = [];
  225. foreach ($designated as $key => $method) {
  226. $defaultMethods["{$client}-{$method}"] = array_merge($record, [
  227. 'key' => $key + 1,
  228. 'method' => $method,
  229. 'is_must_template' => $method != PaymentMethodEnum::BALANCE,
  230. 'is_enable' => $method == PaymentMethodEnum::BALANCE,
  231. ]);
  232. }
  233. return $defaultMethods;
  234. }
  235. /**
  236. * 根据client过滤list
  237. * @param array $listArr
  238. * @param string $client
  239. * @return array|iterable
  240. */
  241. private function listAsClient(array $listArr, string $client)
  242. {
  243. $listAsClient = helper::arrayFilterAsVal($listArr, 'client', $client);
  244. foreach ($listAsClient as &$item) {
  245. $item['is_must_template'] = (bool)$item['is_must_template'];
  246. $item['is_enable'] = (bool)$item['is_enable'];
  247. $item['is_default'] = (bool)$item['is_default'];
  248. }
  249. return $listAsClient;
  250. }
  251. /**
  252. * 根据指定客户端获取可用的支付方式
  253. * @param string $client 客户端来源
  254. * @param bool $balance 是否支持余额支付
  255. * @param int|null $storeId 商城ID
  256. * @return array
  257. * @throws \think\db\exception\DataNotFoundException
  258. * @throws \think\db\exception\DbException
  259. * @throws \think\db\exception\ModelNotFoundException
  260. * @throws BaseException
  261. */
  262. public function getMethodsByClient(string $client, bool $balance = true, int $storeId = null): array
  263. {
  264. $storeId = $storeId ?: self::$storeId;
  265. $group = static::getItem($client, $storeId);
  266. $methods = [];
  267. foreach ($group['methods'] as $method) {
  268. if ($method['is_enable'] && ($balance || $method['method'] !== PaymentMethodEnum::BALANCE)) {
  269. $methods[] = $method;
  270. }
  271. }
  272. if (empty($methods)) {
  273. throwError('很抱歉,当前没有可用的支付方式,请检查后台支付设置');
  274. }
  275. return $methods;
  276. }
  277. /**
  278. * 获取指定的支付方式及模板
  279. * @param string $method 支付方式
  280. * @param string $client 客户端来源
  281. * @param int|null $storeId 商城ID
  282. * @return bool|mixed
  283. * @throws BaseException
  284. * @throws \think\db\exception\DataNotFoundException
  285. * @throws \think\db\exception\DbException
  286. * @throws \think\db\exception\ModelNotFoundException
  287. */
  288. public function getPaymentInfo(string $method, string $client, int $storeId = null)
  289. {
  290. // 获取当前指定的支付方式
  291. $methodInfo = $this->getCurrentMethod($method, $client, $storeId);
  292. // 获取支付模板信息
  293. $methodInfo['template'] = !$methodInfo['is_must_template'] ? [] : $this->getTemplateInfo($methodInfo['template_id']);
  294. return $methodInfo;
  295. }
  296. /**
  297. * 获取支付模板
  298. * @param int $templateId 支付模板ID
  299. * @return array
  300. * @throws BaseException
  301. */
  302. private function getTemplateInfo(int $templateId): array
  303. {
  304. return (new PaymentTemplateModel)->getTemplateInfo($templateId);
  305. }
  306. /**
  307. * 获取当前指定的支付方式
  308. * @param string $method 指定的支付方式
  309. * @param string $client 客户端来源
  310. * @param int|null $storeId 商城ID
  311. * @return bool|mixed
  312. * @throws BaseException
  313. * @throws \think\db\exception\DataNotFoundException
  314. * @throws \think\db\exception\DbException
  315. * @throws \think\db\exception\ModelNotFoundException
  316. */
  317. private function getCurrentMethod(string $method, string $client, int $storeId = null)
  318. {
  319. $methods = $this->getMethodsByClient($client, true, $storeId);
  320. $method = helper::arraySearch($methods, 'method', $method);
  321. if (empty($method)) {
  322. throwError('很抱歉,当前未找到指定的支付方式');
  323. }
  324. return $method;
  325. }
  326. }