Currency.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. <?php
  2. /*
  3. * FecShop file.
  4. *
  5. * @link http://www.fecshop.com/
  6. * @copyright Copyright (c) 2016 FecShop Software LLC
  7. * @license http://www.fecshop.com/license/
  8. */
  9. namespace fecshop\services\page;
  10. use fecshop\services\Service;
  11. use Yii;
  12. use yii\base\InvalidConfigException;
  13. /**
  14. * Page Currency services 货币部分
  15. * @author Terry Zhao <2358269014@qq.com>
  16. * @since 1.0
  17. */
  18. class Currency extends Service
  19. {
  20. const CURRENCY_CURRENT = 'currency_current';
  21. /**
  22. * 该变量用于:在配置文件中,配置所有的货币参数。
  23. * 格式如下:
  24. * [
  25. * 'USD' => [
  26. * 'rate' => 1,
  27. * 'symbol' => '$',
  28. * ],
  29. * 'RMB' => [
  30. * 'rate' => 6.3,
  31. * 'symbol' => 'гд',
  32. * ],
  33. * ].
  34. */
  35. public $currencys;
  36. /**
  37. * 基础货币,产品的价格,填写的都是基础货币的价格。
  38. * 该值需要在配置文件中进行配置.
  39. */
  40. public $baseCurrecy;
  41. /**
  42. * 网站的默认货币,需要注意的是,默认货币不要和基础货币混淆,举例:
  43. * 后台产品统一使用的美元填写产品价格,但是我的网站前端的默认货币为人民币。
  44. * 该值需要在配置文件中进行配置.
  45. */
  46. public $defaultCurrency;
  47. /**
  48. * 当前的货币简码
  49. */
  50. protected $_currentCurrencyCode;
  51. /**
  52. * 根据配置,保存所有货币的配置信息。
  53. */
  54. protected $_currencys;
  55. public function init()
  56. {
  57. parent::init();
  58. // init default and base currency
  59. $this->defaultCurrency = Yii::$app->store->get('base_info', 'default_currency');
  60. $this->baseCurrecy = Yii::$app->store->get('base_info', 'base_currency');
  61. // init all currency
  62. $currencys = Yii::$app->store->get('currency');
  63. if (is_array($currencys)) {
  64. foreach ($currencys as $currency) {
  65. $currency_code = $currency['currency_code'];
  66. $currency_symbol = $currency['currency_symbol'];
  67. $currency_rate = $currency['currency_rate'];
  68. $this->currencys[$currency_code] = [
  69. 'rate' => $currency_rate,
  70. 'symbol' => $currency_symbol
  71. ];
  72. }
  73. }
  74. }
  75. /**
  76. * @param $currencyCode | string 货币简码,譬如USD,RMB等
  77. * @return array
  78. * 如果不传递参数,得到所有的货币
  79. * 如果传递参数,得到的是当前货币的信息。
  80. */
  81. protected function actionGetCurrencys($currencyCode = '')
  82. {
  83. if (!$this->_currencys) {
  84. foreach ($this->currencys as $code => $info) {
  85. $this->_currencys[$code] = [
  86. 'code' => $code,
  87. 'rate' => $info['rate'],
  88. 'symbol' => $info['symbol'],
  89. ];
  90. }
  91. }
  92. if ($currencyCode) {
  93. if (isset($this->_currencys[$currencyCode])) {
  94. return $this->_currencys[$currencyCode];
  95. } else {
  96. $currencyCode = $this->defaultCurrency;
  97. return $this->_currencys[$currencyCode];
  98. }
  99. }
  100. return $this->_currencys;
  101. }
  102. /**
  103. * 得到当前货币的符号,譬如¥ $ 等。
  104. * 如果当前的货币在配置中找不到,则会强制改成默认货币
  105. */
  106. protected function actionGetCurrentSymbol()
  107. {
  108. if (isset($this->currencys[$this->getCurrentCurrency()]['symbol'])) {
  109. return $this->currencys[$this->getCurrentCurrency()]['symbol'];
  110. }
  111. }
  112. /**
  113. * @param $currencyCode | 货币简码
  114. * 得到货币的符号,譬如¥ $ 等。
  115. */
  116. protected function actionGetSymbol($currencyCode)
  117. {
  118. if (isset($this->currencys[$currencyCode]['symbol'])) {
  119. return $this->currencys[$currencyCode]['symbol'];
  120. }
  121. }
  122. /**
  123. * property $price|Float ,默认货币的价格
  124. * Get current currency price. price format is two decimal places,
  125. * if current currency is not find in object variable $currencys(maybe change config in online shop,but current user session is effective),
  126. * current currency will set defaultCurrency, origin price will be return.
  127. * 通过传递默认货币的价格,得到当前货币的价格。
  128. */
  129. protected function actionGetCurrentCurrencyPrice($price)
  130. {
  131. $currencyCode = $this->getCurrentCurrency();
  132. $currencyPrice = $this->getCurrencyPrice($price, $currencyCode);
  133. if ($currencyPrice !== null) {
  134. return $currencyPrice;
  135. }
  136. /*
  137. * 如果上面出现错误,当前的货币在货币配置中找不到,则会使用默认货币
  138. * 这种情况可能出现在货币配置调整的过程中,找不到则会被强制改成默认货币。
  139. */
  140. $this->setCurrentCurrency($this->baseCurrecy);
  141. return $price;
  142. }
  143. /**
  144. * property $price|Float ,默认货币的价格
  145. * property $currencyCode|String,货币简码,譬如 USD
  146. * 根据基础货币,得到相应货币的价格
  147. */
  148. protected function actionGetCurrencyPrice($price, $currencyCode)
  149. {
  150. if (isset($this->currencys[$currencyCode]['rate'])) {
  151. $rate = $this->currencys[$currencyCode]['rate'];
  152. if ($rate) {
  153. return bcmul($price, $rate, 2);
  154. }
  155. }
  156. return null;
  157. }
  158. /**
  159. * @param $current_price | Float 当前货币下的价格
  160. * @return 基础货币下的价格
  161. * 通过当前的货币价格得到基础货币的价格,这是一个反推的过程,
  162. * 需要特别注意的是:这种反推方法换算得到的基础货币的价格,和原来的基础货币价格,
  163. * 可能有0.01的误差,因为默认货币换算成当前货币的算法为小数点后两位进一法得到的。
  164. */
  165. protected function actionGetBaseCurrencyPrice($current_price, $current_currency = '')
  166. {
  167. if (!$current_currency) {
  168. $current_currency = $this->getCurrentCurrency();
  169. }
  170. if (isset($this->currencys[$current_currency]['rate'])) {
  171. $rate = $this->currencys[$current_currency]['rate'];
  172. if ($rate) {
  173. return bcdiv($current_price, $rate, 2);
  174. }
  175. }
  176. }
  177. /**
  178. * @param $currencyCode | 货币简码
  179. * 初始化货币信息,在service Store bootstrap(Yii::$app->store->bootstrap()), 中会被调用
  180. * 1. 如果 $this->defaultCurrency 和 $this->baseCurrecy 没有设置,将会报错。
  181. * 2. 如果 传递参数$currencyCode为空,则会使用默认货币
  182. */
  183. protected function actionInitCurrency($currencyCode = '')
  184. {
  185. if (!$this->defaultCurrency) {
  186. throw new InvalidConfigException('defautlt currency must config');
  187. }
  188. if (!$this->baseCurrecy) {
  189. throw new InvalidConfigException('base currency must config');
  190. }
  191. if (!$this->getCurrentCurrency()) {
  192. if (!$currencyCode) {
  193. $currencyCode = $this->defaultCurrency;
  194. }
  195. $this->setCurrentCurrency($currencyCode);
  196. }
  197. }
  198. /**
  199. * @param $currencyCode | String , 货币简码,如果参数$currencyCode为空,则取当前的货币简码
  200. * @return array
  201. * 得到货币的详细信息,数据格式如下:
  202. * [
  203. * 'code' => $code ,
  204. * 'rate' => $rate ,
  205. * 'symbol' => $symbol ,
  206. * ]
  207. */
  208. protected function actionGetCurrencyInfo($currencyCode = '')
  209. {
  210. if (!$currencyCode) {
  211. $currencyCode = $this->getCurrentCurrency();
  212. }
  213. return $this->getCurrencys($currencyCode);
  214. }
  215. /**
  216. * 得到当前的货币。
  217. */
  218. protected function actionGetCurrentCurrency()
  219. {
  220. if (!$this->_currentCurrencyCode) {
  221. $this->_currentCurrencyCode = Yii::$service->session->get(self::CURRENCY_CURRENT);
  222. }
  223. return $this->_currentCurrencyCode;
  224. }
  225. /**
  226. * @param $currencyCode | String, 当前的货币简码
  227. * 设置当前的货币。
  228. */
  229. protected function actionSetCurrentCurrency($currencyCode)
  230. {
  231. if (!$this->isCorrectCurrency($currencyCode)) {
  232. $currencyCode = $this->defaultCurrency;
  233. }
  234. if ($currencyCode) {
  235. if (!Yii::$service->store->isAppserver()) {
  236. Yii::$service->session->set(self::CURRENCY_CURRENT, $currencyCode);
  237. }
  238. $this->_currentCurrencyCode = $currencyCode;
  239. return true;
  240. }
  241. }
  242. protected $appserverCurrencyHeaderName = 'fecshop-currency';
  243. /**
  244. * appserver端初始化currency
  245. * 初始化货币services,直接从headers中取出来currency。进行set,这样currency就不会从session中读取
  246. * fecshop-2版本对于appserver已经抛弃session servcies
  247. */
  248. public function appserverSetCurrentCurrency()
  249. {
  250. if ($this->_currentCurrencyCode) {
  251. return true;
  252. }
  253. $header = Yii::$app->request->getHeaders();
  254. $currentCurrencyCode = $header[$this->appserverCurrencyHeaderName];
  255. if (!$currentCurrencyCode) {
  256. $currentCurrencyCode = $this->defaultCurrency;
  257. }
  258. if (!$this->isCorrectCurrency($currentCurrencyCode)) {
  259. $currentCurrencyCode = $this->defaultCurrency;
  260. }
  261. $this->_currentCurrencyCode = $currentCurrencyCode;
  262. Yii::$app->response->getHeaders()->set($this->appserverCurrencyHeaderName, $this->_currentCurrencyCode);
  263. }
  264. /**
  265. * @param $currency | String 货币简码
  266. * @return bool
  267. * 检测当前传递的货币简码,是否在配置中存在,如果存在则返回true
  268. */
  269. protected function isCorrectCurrency($currencyCode)
  270. {
  271. if (isset($this->currencys[$currencyCode])) {
  272. return true;
  273. } else {
  274. return false;
  275. }
  276. }
  277. public function setCurrentCurrency2CNY()
  278. {
  279. return $this->setCurrentCurrency('CNY');
  280. }
  281. }