rstorage.php 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. <?php
  2. namespace refill;
  3. use Log;
  4. class system
  5. {
  6. private $mCardType;
  7. private $mOpened;
  8. private $mSpecs;
  9. public function __construct($card_type)
  10. {
  11. $this->mCardType = $card_type;
  12. $this->mSpecs = [];
  13. $this->mOpened = false;
  14. }
  15. public function card_type() {
  16. return $this->mCardType;
  17. }
  18. public function add_amount($amount)
  19. {
  20. $this->mSpecs[] = $amount;
  21. }
  22. public function set_opened($opened) {
  23. $this->mOpened = $opened;
  24. }
  25. public function opened() : bool {
  26. return $this->mOpened;
  27. }
  28. public function total()
  29. {
  30. $amounts = 0;
  31. foreach ($this->mSpecs as $spec) {
  32. $amount = rlock::hget_sys_storage($this->mCardType,$spec);
  33. $amount = intval($amount);
  34. $amount = $amount > 0 ? $amount : 0;
  35. $amounts += $amount;
  36. }
  37. return $amounts;
  38. }
  39. public function spec_total($spec)
  40. {
  41. $amount = rlock::hget_sys_storage($this->mCardType,$spec);
  42. $amount = intval($amount);
  43. return $amount > 0 ? $amount : 0;
  44. }
  45. }
  46. class merchant
  47. {
  48. private $mMchid;
  49. private $mTotalLocks;
  50. private $mSpecLocks;
  51. public function __construct($mchid)
  52. {
  53. $this->mMchid = $mchid;
  54. $this->mTotalLocks = [];
  55. $this->mSpecLocks = [];
  56. }
  57. public function mchid() {
  58. return $this->mMchid;
  59. }
  60. public function set_total_lock($card_type, $lock_type)
  61. {
  62. if ($lock_type != rlock::CLOSE) {
  63. $this->mTotalLocks[$card_type] = $lock_type;
  64. }
  65. }
  66. public function total($card_type)
  67. {
  68. if(array_key_exists($card_type,$this->mTotalLocks)) {
  69. $amount = rlock::hget_mch_total_storage($this->mMchid,$card_type);
  70. $amount = intval($amount);
  71. return $amount > 0 ? $amount : 0;
  72. }
  73. elseif(array_key_exists($card_type, $this->mSpecLocks))
  74. {
  75. $specs = $this->mSpecLocks[$card_type];
  76. $amounts = 0;
  77. foreach ($specs as $spec) {
  78. $amounts += $this->spec_total($card_type,$spec);
  79. }
  80. return $amounts;
  81. }
  82. else {
  83. return 0;
  84. }
  85. }
  86. public function spec_total($card_type,$spec)
  87. {
  88. if (array_key_exists($card_type, $this->mSpecLocks) && array_key_exists($spec, $this->mSpecLocks[$card_type])) {
  89. $amount = rlock::hget_mch_storage($this->mMchid, $card_type, $spec);
  90. $amount = intval($amount);
  91. return $amount > 0 ? $amount : 0;
  92. } else {
  93. return 0;
  94. }
  95. }
  96. public function set_spec_lock($card_type,$spec,$lock_type)
  97. {
  98. if ($lock_type != rlock::CLOSE) {
  99. $this->mSpecLocks[$card_type][$spec] = $lock_type;
  100. }
  101. }
  102. public function has_lock()
  103. {
  104. return !empty($this->mTotalLocks) || !empty($this->mSpecLocks);
  105. }
  106. public function lock_type($card_type,$spec)
  107. {
  108. $total_lock = rlock::CLOSE;
  109. if(array_key_exists($card_type,$this->mTotalLocks)) {
  110. $total_lock = $this->mTotalLocks[$card_type];
  111. }
  112. $spec_lock = rlock::CLOSE;
  113. if(array_key_exists($card_type,$this->mSpecLocks) && array_key_exists($spec,$this->mSpecLocks[$card_type])) {
  114. $spec_lock = $this->mSpecLocks[$card_type][$spec];
  115. }
  116. return [$total_lock,$spec_lock];
  117. }
  118. }
  119. class rstorage
  120. {
  121. private $mSystems;
  122. private $mMerchants;
  123. public function __construct()
  124. {
  125. $this->load();
  126. }
  127. public function load()
  128. {
  129. $this->mSystems = [];
  130. $this->read_sys();
  131. $this->mMerchants = [];
  132. $this->read_merchant();
  133. }
  134. private function locked($card_type)
  135. {
  136. if(array_key_exists($card_type,$this->mSystems)) {
  137. return true;
  138. } else {
  139. return false;
  140. }
  141. }
  142. public function allow($mchid,$card_type,$spec) : bool
  143. {
  144. Log::record("rstorage::allow mchid={$mchid} card_type={$card_type} spec={$spec}",Log::DEBUG);
  145. if(!$this->locked($card_type)) {
  146. Log::record("rstorage::allow {$card_type} locked",Log::DEBUG);
  147. return true;
  148. }
  149. [$total_lock_type,$spec_lock_type] = $this->merchant_lock_type($mchid,$card_type,$spec);
  150. $merchant = $this->mMerchants[$mchid];
  151. Log::record("{$mchid} total_lock:{$total_lock_type} spec_lock:{$spec_lock_type}",Log::DEBUG);
  152. if($spec_lock_type == rlock::ASSIGN) {
  153. $mch_spec_total = $merchant->spec_total($spec);
  154. Log::record("ASSIGN {$mchid} spec_total:{$mch_spec_total}",Log::DEBUG);
  155. return $mch_spec_total >= $spec;
  156. }
  157. elseif($spec_lock_type == rlock::RETAIN)
  158. {
  159. //是否已经满足 Spec
  160. $mch_spec_total = $merchant->spec_total($card_type);
  161. Log::record("ASSIGN {$mchid} spec_total:{$mch_spec_total}",Log::DEBUG);
  162. if($mch_spec_total >= $spec) return true;
  163. }
  164. else {
  165. //CLOSE情况,其它两种情况优先。
  166. }
  167. if ($total_lock_type == rlock::ASSIGN) {
  168. $mch_total = $merchant->total($card_type);
  169. if($mch_total < $spec) return false;
  170. }
  171. $system = $this->mSystems[$card_type];
  172. $total = $system->total();
  173. $spec_total = $system->spec_total($spec);
  174. $diff_total = $total - $this->lowest_total($mchid,$card_type);
  175. $diff_spec_total = $spec_total - $this->lowest_spec_total($mchid,$card_type,$spec);
  176. Log::record("mchid:{$mchid} total:{$total} spec_total:{$spec_total} diff_total:{$diff_total} diff_spec_total={$diff_spec_total}",Log::DEBUG);
  177. return $diff_spec_total >= $spec && $diff_total >= $spec;
  178. }
  179. //return [$toal_lock,$spec_lock]
  180. private function merchant_lock_type($mchid, $card_type, $spec)
  181. {
  182. if(!array_key_exists($mchid,$this->mMerchants)) {
  183. return [rlock::CLOSE,rlock::CLOSE];
  184. }
  185. $merchant = $this->mMerchants[$mchid];
  186. return $merchant->lock_type($card_type, $spec);
  187. }
  188. //需要为锁定的机构保留的最低总量
  189. private function lowest_total($mchid,$card_type)
  190. {
  191. $total = 0;
  192. foreach ($this->mMerchants as $merchant)
  193. {
  194. if($mchid != $merchant->mchid()){
  195. $total += $merchant->total($card_type);
  196. }
  197. }
  198. return $total;
  199. }
  200. //需要为锁定的机构保留的最低总量
  201. private function lowest_spec_total($mchid,$card_type,$spec)
  202. {
  203. $total = 0;
  204. foreach ($this->mMerchants as $merchant)
  205. {
  206. if($mchid != $merchant->mchid()){
  207. $total += $merchant->spec_total($card_type,$spec);
  208. }
  209. }
  210. return $total;
  211. }
  212. private function read_sys()
  213. {
  214. $items = rlock::get_sys();
  215. $parser = function ($key,$val)
  216. {
  217. $datas = explode('-',$key);
  218. $len = count($datas);
  219. if($len != 2) return [false,'','',''];
  220. $card_type = intval($datas[0]);
  221. if($datas[1] == 'open') {
  222. return [true,'open',$card_type,boolval($val)];
  223. }
  224. elseif(is_numeric($datas[1])) {
  225. return [true,'card',$card_type,intval($datas[1])];
  226. }
  227. else {
  228. return [false,'','',''];
  229. }
  230. };
  231. $systems = [];
  232. foreach ($items as $key => $val)
  233. {
  234. [$succ,$name,$card_type,$value] = $parser($key,$val);
  235. if($succ)
  236. {
  237. if(array_key_exists($card_type,$systems)) {
  238. $system = $systems[$card_type];
  239. } else {
  240. $system = new system($card_type);
  241. $systems[$card_type] = $system;
  242. }
  243. if($name == 'open') {
  244. $system->set_opened($value);
  245. }
  246. elseif($name == 'card') {
  247. $system->add_amount($value);
  248. }
  249. }
  250. }
  251. foreach ($systems as $system)
  252. {
  253. if($system->opened()) {
  254. $card_type = $system->card_type();
  255. $this->mSystems[$card_type] = $system;
  256. }
  257. }
  258. }
  259. private function read_merchant()
  260. {
  261. $parser = function ($key,$val,&$merchants)
  262. {
  263. $items = explode('-',$key);
  264. $len = count($items);
  265. if($len < 3) return;
  266. $mchid = intval($items[0]);
  267. if(array_key_exists($mchid,$merchants)) {
  268. $merchant = $merchants[$mchid];
  269. } else {
  270. $merchant = new merchant($mchid);
  271. $merchants[$mchid] = $merchant;
  272. }
  273. $card_type = intval($items[1]);
  274. if($len == 3)
  275. {
  276. if($items[2] == 'turn') {
  277. $lock_type = intval($val);
  278. $merchant->set_total_lock($card_type,$lock_type);
  279. }
  280. }
  281. elseif($len == 4)
  282. {
  283. $amount = intval($items[2]);
  284. if($items[3] == 'turn') {
  285. $lock_type = intval($val);
  286. $merchant->set_spec_lock($card_type,$amount,$lock_type);
  287. }
  288. }
  289. };
  290. $merchants = [];
  291. $items = rlock::get_merchant();
  292. foreach ($items as $key => $val) {
  293. $parser($key, $val, $merchants);
  294. }
  295. foreach ($merchants as $merchant)
  296. {
  297. if($merchant->has_lock()) {
  298. $mchid = $merchant->mchid();
  299. $this->mMerchants[$mchid] = $merchant;
  300. }
  301. }
  302. }
  303. }