rstorage.php 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  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->mSystems = [];
  126. $this->mMerchants = [];
  127. }
  128. public function load()
  129. {
  130. $this->mSystems = [];
  131. $this->read_sys();
  132. $this->mMerchants = [];
  133. $this->read_merchant();
  134. }
  135. private function locked($card_type)
  136. {
  137. if(array_key_exists($card_type,$this->mSystems)) {
  138. return true;
  139. } else {
  140. return false;
  141. }
  142. }
  143. public function allow($mchid,$card_type,$spec) : bool
  144. {
  145. Log::record("rstorage::allow mchid={$mchid} card_type={$card_type} spec={$spec}",Log::DEBUG);
  146. if(!$this->locked($card_type)) {
  147. Log::record("rstorage::allow {$card_type} locked",Log::DEBUG);
  148. return true;
  149. }
  150. [$total_lock_type,$spec_lock_type] = $this->merchant_lock_type($mchid,$card_type,$spec);
  151. $merchant = $this->mMerchants[$mchid];
  152. Log::record("{$mchid} total_lock:{$total_lock_type} spec_lock:{$spec_lock_type}",Log::DEBUG);
  153. if($spec_lock_type == rlock::ASSIGN) {
  154. $mch_spec_total = $merchant->spec_total($spec);
  155. Log::record("ASSIGN {$mchid} spec_total:{$mch_spec_total}",Log::DEBUG);
  156. return $mch_spec_total >= $spec;
  157. }
  158. elseif($spec_lock_type == rlock::RETAIN)
  159. {
  160. //是否已经满足 Spec
  161. $mch_spec_total = $merchant->spec_total($card_type);
  162. Log::record("ASSIGN {$mchid} spec_total:{$mch_spec_total}",Log::DEBUG);
  163. if($mch_spec_total >= $spec) return true;
  164. }
  165. else {
  166. //CLOSE情况,其它两种情况优先。
  167. }
  168. if ($total_lock_type == rlock::ASSIGN) {
  169. $mch_total = $merchant->total($card_type);
  170. if($mch_total < $spec) return false;
  171. }
  172. $system = $this->mSystems[$card_type];
  173. $total = $system->total();
  174. $spec_total = $system->spec_total($spec);
  175. $diff_total = $total - $this->lowest_total($mchid,$card_type);
  176. $diff_spec_total = $spec_total - $this->lowest_spec_total($mchid,$card_type,$spec);
  177. Log::record("mchid:{$mchid} total:{$total} spec_total:{$spec_total} diff_total:{$diff_total} diff_spec_total={$diff_spec_total}",Log::DEBUG);
  178. return $diff_spec_total >= $spec && $diff_total >= $spec;
  179. }
  180. //return [$toal_lock,$spec_lock]
  181. private function merchant_lock_type($mchid, $card_type, $spec)
  182. {
  183. if(!array_key_exists($mchid,$this->mMerchants)) {
  184. return [rlock::CLOSE,rlock::CLOSE];
  185. }
  186. $merchant = $this->mMerchants[$mchid];
  187. return $merchant->lock_type($card_type, $spec);
  188. }
  189. //需要为锁定的机构保留的最低总量
  190. private function lowest_total($mchid,$card_type)
  191. {
  192. $total = 0;
  193. foreach ($this->mMerchants as $merchant)
  194. {
  195. if($mchid != $merchant->mchid()){
  196. $total += $merchant->total($card_type);
  197. }
  198. }
  199. return $total;
  200. }
  201. //需要为锁定的机构保留的最低总量
  202. private function lowest_spec_total($mchid,$card_type,$spec)
  203. {
  204. $total = 0;
  205. foreach ($this->mMerchants as $merchant)
  206. {
  207. if($mchid != $merchant->mchid()){
  208. $total += $merchant->spec_total($card_type,$spec);
  209. }
  210. }
  211. return $total;
  212. }
  213. private function read_sys()
  214. {
  215. $items = rlock::get_sys();
  216. $parser = function ($key,$val)
  217. {
  218. $datas = explode('-',$key);
  219. $len = count($datas);
  220. if($len != 2) return [false,'','',''];
  221. $card_type = intval($datas[0]);
  222. if($datas[1] == 'open') {
  223. return [true,'open',$card_type,boolval($val)];
  224. }
  225. elseif(is_numeric($datas[1])) {
  226. return [true,'card',$card_type,intval($datas[1])];
  227. }
  228. else {
  229. return [false,'','',''];
  230. }
  231. };
  232. $systems = [];
  233. foreach ($items as $key => $val)
  234. {
  235. [$succ,$name,$card_type,$value] = $parser($key,$val);
  236. if($succ)
  237. {
  238. if(array_key_exists($card_type,$systems)) {
  239. $system = $systems[$card_type];
  240. } else {
  241. $system = new system($card_type);
  242. $systems[$card_type] = $system;
  243. }
  244. if($name == 'open') {
  245. $system->set_opened($value);
  246. }
  247. elseif($name == 'card') {
  248. $system->add_amount($value);
  249. }
  250. }
  251. }
  252. foreach ($systems as $system)
  253. {
  254. if($system->opened()) {
  255. $card_type = $system->card_type();
  256. $this->mSystems[$card_type] = $system;
  257. }
  258. }
  259. }
  260. private function read_merchant()
  261. {
  262. $parser = function ($key,$val,&$merchants)
  263. {
  264. $items = explode('-',$key);
  265. $len = count($items);
  266. if($len < 3) return;
  267. $mchid = intval($items[0]);
  268. if(array_key_exists($mchid,$merchants)) {
  269. $merchant = $merchants[$mchid];
  270. } else {
  271. $merchant = new merchant($mchid);
  272. $merchants[$mchid] = $merchant;
  273. }
  274. $card_type = intval($items[1]);
  275. if($len == 3)
  276. {
  277. if($items[2] == 'turn') {
  278. $lock_type = intval($val);
  279. $merchant->set_total_lock($card_type,$lock_type);
  280. }
  281. }
  282. elseif($len == 4)
  283. {
  284. $amount = intval($items[2]);
  285. if($items[3] == 'turn') {
  286. $lock_type = intval($val);
  287. $merchant->set_spec_lock($card_type,$amount,$lock_type);
  288. }
  289. }
  290. };
  291. $merchants = [];
  292. $items = rlock::get_merchant();
  293. foreach ($items as $key => $val) {
  294. $parser($key, $val, $merchants);
  295. }
  296. foreach ($merchants as $merchant)
  297. {
  298. if($merchant->has_lock()) {
  299. $mchid = $merchant->mchid();
  300. $this->mMerchants[$mchid] = $merchant;
  301. }
  302. }
  303. }
  304. }