SaleOrderViewModel.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. using GalaSoft.MvvmLight;
  2. using GalaSoft.MvvmLight.Command;
  3. using GalaSoft.MvvmLight.Ioc;
  4. using Muchinfo.MTPClient.Data;
  5. using Muchinfo.MTPClient.Data.Enums;
  6. using Muchinfo.MTPClient.Data.Model;
  7. using Muchinfo.MTPClient.Data.Model.Account;
  8. using Muchinfo.MTPClient.Data.Model.GoodRules;
  9. using Muchinfo.MTPClient.Data.Model.Sale;
  10. using Muchinfo.MTPClient.Infrastructure.Cache;
  11. using Muchinfo.MTPClient.Infrastructure.Helpers;
  12. using Muchinfo.MTPClient.Infrastructure.MessageBox;
  13. using Muchinfo.MTPClient.Infrastructure.Utilities;
  14. using Muchinfo.MTPClient.IService;
  15. using Muchinfo.MTPClient.Resources;
  16. using Muchinfo.WPF.Controls.Windows;
  17. using System;
  18. using System.Collections.Generic;
  19. using System.Linq;
  20. //----------------------------------------------------------------
  21. //Module Name: $safeprojectname$
  22. //Purpose:
  23. //CopyRight: Muchinfo
  24. //History:
  25. //----------------------------------------------------------------
  26. //DateTime 2016/4/5 9:51:28
  27. //Author
  28. //Description Create
  29. //----------------------------------------------------------------
  30. using System.Windows;
  31. namespace Muchinfo.MTPClient.Sale.ViewModels
  32. {
  33. public class SaleOrderViewModel : ViewModelBase
  34. {
  35. private Direction _direction; ////买卖方向
  36. private Window _openWindow; ///下单窗口
  37. protected IGoodsService _goodsService;
  38. private ePriceMode _priceMode;
  39. /// <summary>
  40. /// 当前账号
  41. /// </summary>
  42. public TradeAccount CurrentAccount
  43. {
  44. get
  45. {
  46. return UserManager.CurrentTradeAccount;
  47. }
  48. }
  49. /// <summary>
  50. /// 取价方式
  51. /// </summary>
  52. public ePriceMode PriceMode
  53. {
  54. get { return _priceMode; }
  55. set
  56. {
  57. Set(() => PriceMode, ref _priceMode, value);
  58. }
  59. }
  60. /// <summary>
  61. /// 买卖方向
  62. /// </summary>
  63. public Direction Direction
  64. {
  65. get
  66. {
  67. return _direction;
  68. }
  69. set
  70. {
  71. if (value == Direction.unSet)
  72. {
  73. return;
  74. }
  75. Set(() => Direction, ref _direction, value);
  76. }
  77. }
  78. private string _winTitle;
  79. /// <summary>
  80. /// 标题
  81. /// </summary>
  82. public string WinTitle
  83. {
  84. get { return _winTitle; }
  85. set { Set(() => WinTitle, ref _winTitle, value); }
  86. }
  87. private List<SaleGoods> _saleGoodses;
  88. /// <summary>
  89. /// 发售商品
  90. /// </summary>
  91. public List<SaleGoods> SaleGoodses
  92. {
  93. get { return _saleGoodses; }
  94. set { Set(() => SaleGoodses, ref _saleGoodses, value); }
  95. }
  96. private SaleGoods _currentSaleGoods;
  97. /// <summary>
  98. /// 当前发售商品
  99. /// </summary>
  100. public SaleGoods CurrentSaleGoods
  101. {
  102. get { return _currentSaleGoods; }
  103. set
  104. {
  105. Set(() => CurrentSaleGoods, ref _currentSaleGoods, value);
  106. SetGoodsInit();
  107. }
  108. }
  109. private decimal _executePrice;
  110. /// <summary>
  111. /// 委托价格
  112. /// </summary>
  113. public decimal ExecutePrice
  114. {
  115. get { return _executePrice; }
  116. set
  117. {
  118. Set(() => ExecutePrice, ref _executePrice, value);
  119. }
  120. }
  121. private decimal _lot = decimal.Zero;
  122. /// <summary>
  123. /// 数量
  124. /// </summary>
  125. public decimal Lot
  126. {
  127. get
  128. {
  129. return _lot;
  130. }
  131. set
  132. {
  133. Set(() => Lot, ref _lot, value);
  134. _agreeUnitLot = (_currentSaleGoods == null) ? "0" : _currentSaleGoods.AgreeUnit * _lot + string.Empty;
  135. RaisePropertyChanged(() => AgreeUnitLot);
  136. }
  137. }
  138. private bool _oKButtonEnabled = true;
  139. /// <summary>
  140. ///设置按键不可用
  141. /// </summary>
  142. public bool OKButtonEnabled
  143. {
  144. get
  145. {
  146. return _oKButtonEnabled;
  147. }
  148. set
  149. {
  150. Set(() => OKButtonEnabled, ref _oKButtonEnabled, value);
  151. }
  152. }
  153. private bool _isBusy;
  154. /// <summary>
  155. /// 是否忙
  156. /// </summary>
  157. public bool IsBusy
  158. {
  159. get { return _isBusy; }
  160. set { Set(() => IsBusy, ref _isBusy, value); }
  161. }
  162. private decimal _quotePrice; //当前行情价
  163. /// <summary>
  164. /// 当前行情价
  165. /// </summary>
  166. public decimal QuotePrice
  167. {
  168. get
  169. {
  170. return _quotePrice;
  171. }
  172. set
  173. {
  174. Set(() => QuotePrice, ref _quotePrice, value);
  175. }
  176. }
  177. #region 申购单位
  178. private decimal _perOrderQty = decimal.Zero;
  179. /// <summary>
  180. /// 申购单位
  181. /// </summary>
  182. public decimal PerOrderQty
  183. {
  184. get
  185. {
  186. return _perOrderQty;
  187. }
  188. set
  189. {
  190. Set(() => PerOrderQty, ref _perOrderQty, value);
  191. }
  192. }
  193. #endregion
  194. #region 最小数量
  195. private decimal _minLot;
  196. /// <summary>
  197. /// 最小数量
  198. /// </summary>
  199. public decimal MinLot
  200. {
  201. get { return _minLot; }
  202. set { Set(() => MinLot, ref _minLot, value); }
  203. }
  204. #endregion
  205. private decimal _maxLot;
  206. /// <summary>
  207. /// 最大数量
  208. /// </summary>
  209. public decimal MaxLot
  210. {
  211. get { return _maxLot; }
  212. set { Set(() => MaxLot, ref _maxLot, value); }
  213. }
  214. private string _agreeUnitLot;
  215. /// <summary>
  216. /// 合约数量
  217. /// </summary>
  218. public string AgreeUnitLot
  219. {
  220. get { return _agreeUnitLot; }
  221. set { Set(() => AgreeUnitLot, ref _agreeUnitLot, value); }
  222. }
  223. /// <summary>
  224. /// 下单确定
  225. /// </summary>
  226. public RelayCommand<Window> OKCommand
  227. {
  228. get
  229. {
  230. return new RelayCommand<Window>((dialog) =>
  231. {
  232. OKButtonEnabled = false;
  233. string errorMsg = string.Empty;
  234. //bool validateBool = true;////内容验证
  235. bool validateBool = Validated(ref errorMsg); ////内容验证
  236. if (validateBool)
  237. {
  238. _openWindow = dialog;
  239. var newOrder = new NewEntrustOrder()
  240. {
  241. BuyOrSell = Direction,
  242. OperaterId = UserManager.CurrentTradeAccount.AccountId,
  243. // GoodsCode = this.CurrentGoods.GoodsCode,
  244. // MarketId = (uint)this.CurrentSaleGoods.MarketId,
  245. GoodsId = (uint)CurrentSaleGoods.GoodsId,
  246. AccountType = UserManager.CurrentTradeAccount.AccountType,
  247. BuildType = OpenCloseMode.BUILDTYPE_OPEN,
  248. EntrurstTime = ApplicationParameter.ServerTimeNow,
  249. MemberAreaId = UserManager.CurrentTradeAccount.MemberAreaId,
  250. EntrustQuantity = Lot,
  251. PriceMode = this.PriceMode,
  252. };
  253. // if (UserManager.CurrentTradeAccount.FundsAccounts.Any() &&
  254. //UserManager.CurrentTradeAccount.FundsAccounts[0] != null)
  255. // {
  256. // newOrder.AccountId = UserManager.CurrentTradeAccount.FundsAccounts[0].AccountId;
  257. // }
  258. // else
  259. // {
  260. // newOrder.AccountId = UserManager.CurrentTradeAccount.AccountId;
  261. // }
  262. newOrder.EntrustPrice = PriceMode == ePriceMode.PRICEMODE_LIMIT ? ExecutePrice : QuotePrice;
  263. // newOrder.CurtQuotePrice = QuotePrice;
  264. if (ComfirmCheck(newOrder))
  265. {
  266. IsBusy = true;
  267. var saleService = SimpleIoc.Default.GetInstance<ISaleService>();
  268. saleService.SaleEntrurstOrder(newOrder, EntrurstSuccessCallBack, EntrurstErrorCallBack);
  269. }
  270. else
  271. {
  272. OKButtonEnabled = true;
  273. }
  274. }
  275. else
  276. {
  277. MessageBoxHelper.ShowInfo(errorMsg, Client_Resource.MessageBox_Error_Title);
  278. OKButtonEnabled = true;
  279. }
  280. });
  281. }
  282. }
  283. private bool ComfirmCheck(NewEntrustOrder order)
  284. {
  285. var userInfo = UserManager.GetCurrentUserInfo(); ////交易菜单设置
  286. if (userInfo.TradeParams == null)
  287. {
  288. userInfo.TradeParams = new TradeParams();
  289. }
  290. var result = true;
  291. if (userInfo.TradeParams.IsOrderComfrim)
  292. {
  293. var comfim = new OrderComfirmModel()
  294. {
  295. GoodsName = CurrentSaleGoods.GoodsName,
  296. Lot = order.EntrustQuantity,
  297. Direction = order.BuyOrSell ,
  298. OrderPrice = order.EntrustPrice,
  299. };
  300. var comfirm = new OrderComfirm() {DataContext = comfim, Owner = Application.Current.MainWindow};
  301. if (comfirm.ShowDialog() != true)
  302. {
  303. result = false;
  304. }
  305. }
  306. return result;
  307. }
  308. /// <summary>
  309. /// 快速下单窗口取消
  310. /// </summary>
  311. public RelayCommand<Window> CancelCommand
  312. {
  313. get
  314. {
  315. return new RelayCommand<Window>((dialog) =>
  316. {
  317. dialog.DialogResult = false;
  318. });
  319. }
  320. }
  321. /// <summary>
  322. /// 提交成功返回
  323. /// </summary>
  324. /// <param name="order"></param>
  325. private void EntrurstSuccessCallBack(OrderDetail order)
  326. {
  327. IsBusy = false;
  328. Application.Current.Dispatcher.BeginInvoke(new Action(() =>
  329. {
  330. OKButtonEnabled = true;
  331. // IsBusy = false;
  332. CloseOrderWin();
  333. }));
  334. MessengerHelper.DefaultSend(UserManager.CurrentTradeAccount, MessengerTokens.OrderNoticeToken);
  335. }
  336. /// <summary>
  337. /// 下单关窗口
  338. /// </summary>
  339. private void CloseOrderWin()
  340. {
  341. var userInfo = UserManager.GetCurrentUserInfo(); ////交易菜单设置
  342. if (userInfo.TradeParams == null)
  343. {
  344. userInfo.TradeParams = new TradeParams();
  345. }
  346. if (userInfo.TradeParams.IsSuccessComfrim) ////下单成功是否关窗口
  347. {
  348. MessageBoxHelper.ShowSuccess(Client_Resource.Order_Success_Result,
  349. Client_Resource.Open_MessageBox_Title);
  350. }
  351. if (_openWindow != null)
  352. {
  353. _openWindow.Close();
  354. this.Cleanup();
  355. }
  356. }
  357. /// <summary>
  358. /// 委托失败返回
  359. /// </summary>
  360. /// <param name="errorEntity"></param>
  361. private void EntrurstErrorCallBack(ErrorEntity errorEntity)
  362. {
  363. IsBusy = false;
  364. Application.Current.Dispatcher.BeginInvoke(new Action(() =>
  365. {
  366. OKButtonEnabled = true;
  367. ErrorManager.ShowReturnError(errorEntity, Client_Resource.UI2014_Tips, true);
  368. if (_openWindow != null)
  369. {
  370. _openWindow.Close();
  371. this.Cleanup();
  372. }
  373. // IsBusy = false;
  374. }));
  375. }
  376. public SaleOrderViewModel(SaleGoods saleGoods)
  377. {
  378. _goodsService = SimpleIoc.Default.GetInstance<IGoodsService>();
  379. if (CacheManager.SaleGoodses != null && CacheManager.SaleGoodses.Any())
  380. {
  381. var goodsList = new List<SaleGoods>();
  382. foreach (var key in CacheManager.SaleGoodses.Keys)
  383. {
  384. goodsList.AddRange(CacheManager.SaleGoodses[key]);
  385. }
  386. SaleGoodses = goodsList.Where((item) => item.RunSteps == eRunStep.RUNSTEP_BIDDINGPRICE).ToList();
  387. }
  388. CurrentSaleGoods = saleGoods;
  389. //NEW 申购单位 【错误 #29137】
  390. var tempPerOrderQty = _goodsService.GetGoodsParamerRule((int)CurrentSaleGoods.GoodsId, CurrentSaleGoods.TradeMode, GoodsTradeConts.MinSalePerOrderQty);
  391. PerOrderQty = tempPerOrderQty.FeeValue;
  392. Lot = PerOrderQty;
  393. }
  394. private void SetGoodsInit()
  395. {
  396. if (CurrentSaleGoods != null)
  397. {
  398. PerOrderQty = 1;
  399. var tempPerOrderQty = _goodsService.GetGoodsParamerRule((int)CurrentSaleGoods.GoodsId, CurrentSaleGoods.TradeMode, GoodsTradeConts.MinSalePerOrderQty);
  400. if (tempPerOrderQty != null)
  401. {
  402. PerOrderQty = tempPerOrderQty.FeeValue;
  403. }
  404. QuotePrice = ExecutePrice = CurrentSaleGoods.SalePrice;
  405. Lot = PerOrderQty;
  406. MaxLot = Math.Round(_currentSaleGoods.PerMaxSubQty, 2, MidpointRounding.AwayFromZero);
  407. MinLot = Math.Round(_currentSaleGoods.PerMinSubQty, 2, MidpointRounding.AwayFromZero);
  408. var enableOpenNum = GetEnableNum(ExecutePrice); //根据资金算出可建仓数
  409. if (enableOpenNum > 0)
  410. {
  411. //enableOpenNum = _currentSaleGoods.PerMinSubQty == 0 ? enableOpenNum : Math.Floor(enableOpenNum / _currentSaleGoods.PerMinSubQty) * _currentSaleGoods.PerMinSubQty; ////下单数量应该为最小的整数倍
  412. enableOpenNum = PerOrderQty == 0 ? enableOpenNum : Math.Floor(enableOpenNum / PerOrderQty) * PerOrderQty; ////下单数量应该为申购单位的整数倍
  413. MaxLot = Math.Min(enableOpenNum, MaxLot);
  414. }
  415. else
  416. {
  417. MaxLot = decimal.Zero;
  418. }
  419. MaxLot = Math.Round(MaxLot, 2, MidpointRounding.AwayFromZero);
  420. MinLot = Math.Round(MinLot, 2, MidpointRounding.AwayFromZero);
  421. }
  422. }
  423. public bool Validated(ref string msg)
  424. {
  425. if (Lot.ToString().Length <= 0 || Lot <= 0 || Lot == decimal.Zero || Lot > MaxLot)
  426. {
  427. //数量不在正确范围内
  428. msg = Muchinfo.MTPClient.Resources.Client_Resource.ErrorNumRange;
  429. return false;
  430. }
  431. if (Lot > CurrentSaleGoods.PerMaxSubQty)
  432. {
  433. //msg = "申购数量超过单笔最大申购数量";
  434. msg = Muchinfo.MTPClient.Resources.Client_Resource.ErrorSaleNum;
  435. return false;
  436. }
  437. if (Lot < CurrentSaleGoods.PerMinSubQty)
  438. {
  439. //msg = "申购数量应大于单笔最小申购数量";
  440. msg = string.Format(Muchinfo.MTPClient.Resources.Client_Resource.Error_SaleNum, CurrentSaleGoods.PerMinSubQty);
  441. return false;
  442. }
  443. if (Lot != 0 && (Lot % PerOrderQty) != 0)
  444. {
  445. //数量输入有误!应为{设定申购单位}的倍数.
  446. msg = string.Format(Muchinfo.MTPClient.Resources.Client_Resource.SaleOrderViewModel_InputNumShouldBeRight, PerOrderQty);
  447. return false;
  448. }
  449. return true;
  450. }
  451. /// <summary>
  452. /// 根据可用资金算出可下单的数量
  453. /// </summary>
  454. /// <returns></returns>
  455. protected decimal GetEnableNum(decimal price)
  456. {
  457. decimal enablenum = 0;
  458. decimal usableFunds = 0;
  459. decimal dividernum = 0;
  460. //可用资金
  461. usableFunds = UserManager.CurrentAccountUsableFunds();
  462. dividernum = GetDivider(price);
  463. if (dividernum != 0)
  464. {
  465. var calcLot = usableFunds / dividernum;
  466. if (calcLot <= 0)
  467. {
  468. enablenum = 0;
  469. }
  470. else if (calcLot >= int.MaxValue)
  471. {
  472. enablenum = int.MaxValue;
  473. }
  474. else
  475. {
  476. enablenum = calcLot; //数量
  477. }
  478. }
  479. return enablenum > 0 ? enablenum : 0;
  480. }
  481. /// <summary>
  482. /// 每手下单所需资金
  483. /// </summary>
  484. /// <param name="price">价格</param>
  485. /// <returns></returns>
  486. private decimal GetDivider(decimal price)
  487. {
  488. decimal dividernum = 0;
  489. decimal dividernumChange = 0;
  490. if (Direction == Direction.Bid)
  491. {
  492. //【买】建仓手续费
  493. dividernumChange = GetTradeFeeBy(eTradeFeeType.TRADEFEETYPE_TRADECHARGE, price);
  494. }
  495. else
  496. {
  497. //【卖】建仓手续费
  498. dividernumChange = GetTradeFeeBy(eTradeFeeType.TRADEFEETYPE_TRADECHARGE, price);
  499. }
  500. //竞价全额
  501. if (CurrentSaleGoods != null && CurrentSaleGoods.MoneyMode == eMoneyMode.MONEYMODE_PAY)
  502. {
  503. //dividernum = _currentGoods.CurrentPrice == 0 ? _currentGoods.LastClose : _currentGoods.CurrentPrice;
  504. dividernum = price * CurrentSaleGoods.AgreeUnit + dividernumChange;
  505. return dividernum;
  506. }
  507. return GetTradeFeeBy(eTradeFeeType.TRADEFEETYPE_TRADECHARGE, price) + dividernumChange;
  508. }
  509. /// <summary>
  510. /// 获取指定【交易费用类型】的费用
  511. /// </summary>
  512. /// <param name="tradeFeeType"></param>
  513. /// <param name="price"></param>
  514. /// <returns></returns>
  515. private decimal GetTradeFeeBy(eTradeFeeType tradeFeeType, decimal price)
  516. {
  517. decimal dividerTradeFee = 0;
  518. #region 类型:建仓保证金
  519. //获取交易费用类型=建仓保证金
  520. var eTradeFee = _goodsService.GetTradeFee(CurrentSaleGoods.TradeMode, tradeFeeType);
  521. GoodsFeeType goodsfee = null;
  522. GoodsFeeType accountfee = null;
  523. #endregion
  524. if (CurrentSaleGoods != null && CacheManager.TradeGoodsFeeRules != null && CacheManager.TradeGoodsFeeRules.ContainsKey((int)CurrentSaleGoods.GoodsId))
  525. {
  526. #region 类型:建仓保证金
  527. if (CacheManager.TradeGoodsFeeRules[(int)CurrentSaleGoods.GoodsId].GoodsFees.ContainsKey((int)eTradeFee))
  528. {
  529. goodsfee = CacheManager.TradeGoodsFeeRules[(int)CurrentSaleGoods.GoodsId].GoodsFees[(int)eTradeFee];
  530. }
  531. else if (CacheManager.TradeGoodsFeeRules[(int)CurrentSaleGoods.GoodsId].AccountGoodsFees.ContainsKey((int)eTradeFee))
  532. {
  533. accountfee = CacheManager.TradeGoodsFeeRules[(int)CurrentSaleGoods.GoodsId].AccountGoodsFees[(int)eTradeFee];
  534. }
  535. #endregion
  536. }
  537. #region 类型:建仓保证金
  538. //商品是总额百分比模式
  539. if (goodsfee != null && (int)eCalMode.CALMODE_FIXEDRATIO == goodsfee.FeeMode)
  540. {
  541. //可用资金/合约单位*价格*占用百分比 或者可用资金/合约单位固定值
  542. if (accountfee != null)
  543. {
  544. switch ((int)accountfee.FeeMode)
  545. {
  546. case (int)eCalMode.CALMODE_FIXEDRATIO:
  547. dividerTradeFee = (CurrentSaleGoods.AgreeUnit) * price * (accountfee.FeeValue + goodsfee.FeeValue);
  548. break;
  549. case (int)eCalMode.CALMODE_FIXEDNUMBER:
  550. dividerTradeFee = (CurrentSaleGoods.AgreeUnit) * price * goodsfee.FeeValue + accountfee.FeeValue;
  551. break;
  552. }
  553. }
  554. else
  555. {
  556. dividerTradeFee = (CurrentSaleGoods.AgreeUnit) * price * goodsfee.FeeValue;
  557. }
  558. }
  559. //商品是合约单位固定值的模式
  560. else if (goodsfee != null && (int)eCalMode.CALMODE_FIXEDNUMBER == goodsfee.FeeMode)
  561. {
  562. //可用资金/合约单位*价格*占用百分比 或者可用资金/合约单位固定值
  563. if (accountfee != null)
  564. {
  565. switch ((int)accountfee.FeeMode)
  566. {
  567. case (int)eCalMode.CALMODE_FIXEDRATIO:
  568. dividerTradeFee = (CurrentSaleGoods.AgreeUnit) * price * accountfee.FeeValue + goodsfee.FeeValue;
  569. break;
  570. case (int)eCalMode.CALMODE_FIXEDNUMBER:
  571. dividerTradeFee = accountfee.FeeValue + goodsfee.FeeValue;
  572. break;
  573. }
  574. }
  575. else
  576. {
  577. dividerTradeFee = goodsfee.FeeValue;
  578. }
  579. }
  580. #endregion
  581. return dividerTradeFee;
  582. }
  583. }
  584. }