Exemple #1
0
        private Order Generate(MerchantAccount account, Cryptocurrency coin, string unifiedFiatCurrency, string fiatCurrency, decimal amount, PaymentType paymentType, string merchantClientIP = null)
        {
            var order = new Order
            {
                Id                  = Guid.NewGuid(),
                OrderNo             = NumberGenerator.GenerateUnixOrderNo(),
                MerchantAccountId   = account.Id,
                CryptoId            = coin.Id,
                CryptoCode          = coin.Code,
                FiatAmount          = amount,
                PaymentType         = paymentType,
                FiatCurrency        = fiatCurrency,
                Status              = OrderStatus.Pending,
                Timestamp           = DateTime.UtcNow,
                ExpiredTime         = DateTime.UtcNow.AddMinutes(30),
                Markup              = account.Markup,
                ExchangeRate        = GetExchangeRate(account.CountryId, fiatCurrency, coin),
                UnifiedExchangeRate = GetExchangeRate(account.CountryId, unifiedFiatCurrency, coin),
                UnifiedFiatCurrency = unifiedFiatCurrency,
                MerchantIP          = merchantClientIP
            };

            var calcModel =
                CalculateAmount(amount, account.Markup, account.Receivables_Tier, order.ExchangeRate, coin);

            order.ActualFiatAmount   = calcModel.FiatTotalAmount;
            order.CryptoAmount       = calcModel.CryptoAmount;
            order.TransactionFee     = calcModel.TransactionFee;
            order.ActualCryptoAmount = calcModel.ActualCryptoAmount;

            var model = CalculateUnifiedAmount(order.CryptoAmount, order.ActualCryptoAmount, order.UnifiedExchangeRate);

            order.UnifiedFiatAmount       = model.UnifiedFiatAmount;
            order.UnifiedActualFiatAmount = model.UnifiedActualFiatAmount;
            return(order);
        }
Exemple #2
0
        private void MiningReceived(WalletFactory _walletFactory, DepositFactory _depositFactory, WalletStatementFactory _walletStatementFactory, TransactionFactory _transactionFactory,
                                    long requestId, string transactionId, Guid accountId, decimal amount)
        {
            if (RedisHelper.KeyExists(miningReceivedKey + requestId))//防止没写进数据库之前,相同的请求调用
            {
                throw new CommonException(20001, "Error: Repeated requests");
            }

            var excistDeposit = _depositFactory.GetByRequestId(accountId, requestId);

            if (excistDeposit != null)
            {
                throw new CommonException(20001, "Error: Repeated requests");
            }

            RedisHelper.StringSet(miningReceivedKey + requestId, "1", new TimeSpan(0, 0, 30));

            var crypto = new CryptocurrencyDAC().GetByCode("FIII");

            if (crypto == null)
            {
                throw new CommonException(20000, "Error: Invalid cryptocurrency");
            }

            var wallet = _walletFactory.GetByAccountId(accountId, crypto.Id);

            var timestamp = DateTime.UtcNow;

            using (var scope = new TransactionScope())
            {
                if (wallet == null)
                {
                    wallet = GenerateWallet(_walletFactory, accountId, crypto.Id, crypto.Code);
                }

                var deposit = new Deposit
                {
                    AccountId     = accountId,
                    WalletId      = wallet.Id,
                    FromType      = DepositFromType.PosMining,
                    ToAddress     = wallet.Address,
                    Amount        = amount,
                    Status        = TransactionStatus.Confirmed,
                    Timestamp     = timestamp,
                    RequestId     = requestId,
                    OrderNo       = NumberGenerator.GenerateUnixOrderNo(),
                    TransactionId = transactionId,
                    CryptoCode    = crypto.Code
                };
                _depositFactory.Insert(deposit);
                _transactionFactory.Insert(new UserTransaction
                {
                    Id         = Guid.NewGuid(),
                    AccountId  = accountId,
                    CryptoId   = crypto.Id,
                    CryptoCode = crypto.Code,
                    Type       = UserTransactionType.Deposit,
                    DetailId   = deposit.Id.ToString(),
                    Status     = (byte)deposit.Status,
                    Timestamp  = deposit.Timestamp,
                    Amount     = amount,
                    OrderNo    = deposit.OrderNo
                });
                _walletFactory.Increase(wallet.Id, amount);
                //_walletFactory.DecreaseFreeze(wallet.Id, -amount);
                _walletStatementFactory.Insert(new WalletStatement
                {
                    Action        = Entities.UserWalletStatementAction.AwardDeposit,
                    Amount        = amount,
                    Balance       = wallet.Balance + amount,
                    FrozenAmount  = 0,
                    FrozenBalance = wallet.FrozenBalance,
                    Remark        = null,
                    Timestamp     = timestamp,
                    WalletId      = wallet.Id
                });
                scope.Complete();
            }
        }
        //private readonly Dictionary<string, int> _notificationErrorCount = new Dictionary<string, int>();

        public void Payment(string message)
        {
            var orderModel = JsonConvert.DeserializeObject <MallPaymentOrder>(message);

            var userWalletDac      = new UserWalletDAC();
            var walletStatementDac = new UserWalletStatementDAC();
            var gatewayOrderDac    = new GatewayOrderDAC();
            var mallDac            = new MallPaymentOrderDAC();
            var cryptoDac          = new CryptocurrencyDAC();

            var extsis = gatewayOrderDac.GetByOrderNo(orderModel.OrderId);

            if (extsis != null && extsis.Status == GatewayOrderStatus.Completed)
            {
                _log.Info("Order message " + message + " hased Payment.");
                return;
            }

            var cryptoFiii = cryptoDac.GetByCode("FIII");
            var fiiiWallet = userWalletDac.GetByAccountId(orderModel.UserAccountId, cryptoFiii.Id);

            if (fiiiWallet.Balance < orderModel.CryptoAmount)
            {
                _log.ErrorFormat("message {0}, Insufficient balance", message);
            }

            try
            {
                var fiiiPrice      = GetMarketPrice("USD", "FIII");
                var fiiiFiatAmount = Math.Round(orderModel.CryptoAmount * fiiiPrice, 2);

                var trdeNo = NumberGenerator.GenerateUnixOrderNo();
                var id     = Guid.NewGuid();
                using (var scope = new TransactionScope())
                {
                    userWalletDac.Decrease(fiiiWallet.Id, orderModel.CryptoAmount);
                    walletStatementDac.Insert(new UserWalletStatement
                    {
                        WalletId      = fiiiWallet.Id,
                        Action        = UserWalletStatementAction.Consume,
                        Amount        = -orderModel.CryptoAmount,
                        Balance       = fiiiWallet.Balance - orderModel.CryptoAmount,
                        FrozenAmount  = 0,
                        FrozenBalance = fiiiWallet.FrozenBalance,
                        Timestamp     = DateTime.UtcNow
                    });

                    var gatewayFiiiOrder = new GatewayOrder
                    {
                        Id                 = id,
                        OrderNo            = orderModel.OrderId,
                        MerchantAccountId  = Guid.Empty,
                        MerchantName       = "FiiiShop",
                        CryptoId           = cryptoFiii.Id,
                        CryptoCode         = "FIII",
                        FiatAmount         = fiiiFiatAmount,
                        FiatCurrency       = "USD",
                        Status             = GatewayOrderStatus.Completed,
                        ExpiredTime        = DateTime.UtcNow.AddMinutes(30),
                        Markup             = 0M,
                        ExchangeRate       = fiiiPrice,
                        PaymentTime        = DateTime.UtcNow,
                        Timestamp          = DateTime.UtcNow,
                        UserAccountId      = orderModel.UserAccountId,
                        ActualCryptoAmount = orderModel.CryptoAmount,
                        ActualFiatAmount   = fiiiFiatAmount,
                        CryptoAmount       = orderModel.CryptoAmount,
                        TransactionFee     = 0,
                        Remark             = null,
                        TradeNo            = trdeNo
                    };
                    gatewayOrderDac.Insert(gatewayFiiiOrder);

                    mallDac.UpdateStatus(orderModel.Id, (byte)OrderStatus.Completed);
                    mallDac.UpdateTradeNo(orderModel.Id, trdeNo);

                    scope.Complete();
                }

                RabbitMQSender.SendMessage("ShopPayment", id);
                SendNotificationMessage(TradeType.Payment, orderModel.Id, orderModel.OrderId, trdeNo, "success");
            }
            catch (Exception exception)
            {
                //SendNotificationMessage(TradeType.Payment, orderModel.Id, orderModel.OrderId, string.Empty, "error");
                _log.Error("Payment error, exception : " + exception.Message);
            }
        }
        public void Refund(string message)
        {
            var orderModel = JsonConvert.DeserializeObject <MallPaymentOrder>(message);

            var userWalletDac      = new UserWalletDAC();
            var walletStatementDac = new UserWalletStatementDAC();
            var gatewayOrderDac    = new GatewayOrderDAC();
            var mallDac            = new MallPaymentOrderDAC();
            var refundDac          = new GatewayRefundOrderDAC();

            var gatewayOrder = gatewayOrderDac.GetByTradeNo(orderModel.TradeNo);

            if (gatewayOrder.Status == GatewayOrderStatus.Pending)
            {
                _log.Error("Order message " + message + " not payment.");
                return;
            }
            if (gatewayOrder.Status == GatewayOrderStatus.Refunded)
            {
                _log.Info("Order message " + message + " has refund.");
                return;
            }

            var fiiiWallet = userWalletDac.GetByCryptoCode(orderModel.UserAccountId, "FIII");

            try
            {
                var id            = Guid.NewGuid();
                var refundTradeNo = NumberGenerator.GenerateUnixOrderNo();
                using (var scope = new TransactionScope())
                {
                    mallDac.UpdateStatus(orderModel.Id, (byte)OrderStatus.Refunded);
                    mallDac.UpdateRefundTradeNo(orderModel.Id, refundTradeNo);

                    gatewayOrderDac.UpdateStatus(gatewayOrder.Id, (byte)OrderStatus.Refunded);

                    userWalletDac.Increase(fiiiWallet.Id, gatewayOrder.CryptoAmount);
                    walletStatementDac.Insert(new UserWalletStatement
                    {
                        WalletId      = fiiiWallet.Id,
                        Action        = UserWalletStatementAction.Refund,
                        Amount        = orderModel.CryptoAmount,
                        Balance       = fiiiWallet.Balance + gatewayOrder.CryptoAmount,
                        FrozenAmount  = 0,
                        FrozenBalance = fiiiWallet.FrozenBalance,
                        Timestamp     = DateTime.UtcNow
                    });

                    refundDac.Insert(new GatewayRefundOrder
                    {
                        Id            = id,
                        OrderId       = gatewayOrder.Id,
                        Remark        = "",
                        Status        = RefundStatus.Completed,
                        Timestamp     = DateTime.UtcNow,
                        RefundTradeNo = refundTradeNo
                    });

                    scope.Complete();
                }

                RabbitMQSender.SendMessage("ShopPaymentRefund", id);
                SendNotificationMessage(TradeType.Refund, orderModel.Id, orderModel.OrderId, refundTradeNo, "success");
            }
            catch (Exception exception)
            {
                _log.Error("Refund error, exception : " + exception.Message);

                //SendNotificationMessage(TradeType.Refund, orderModel.Id, orderModel.OrderId, string.Empty, "error");
            }
        }
        public string CreateOrder(Guid merchantAccountId, string fiatCurrency, int cryptoId, decimal amount, PaymentType paymentType, string userToken, string clientIP)
        {
            var accountDAC = new MerchantAccountDAC();

            var account = accountDAC.GetById(merchantAccountId);

            if (!account.IsAllowAcceptPayment)
            {
                throw new CommonException(ReasonCode.Not_Allow_Withdrawal, Resources.禁止收款);
            }

            var coin = new CryptocurrencyDAC().GetById(cryptoId);

            if (!coin.Status.HasFlag(CryptoStatus.Pay))
            {
                throw new CommonException(ReasonCode.CURRENCY_FORBIDDEN, Resources.CurrencyForbidden);
            }

            if (coin.Enable == (byte)CurrencyStatus.Forbidden)
            {
                throw new CommonException(ReasonCode.CURRENCY_FORBIDDEN, Resources.CurrencyForbidden);
            }

            var order = new RedisOrderDTO()
            {
                FiatAmount   = amount,
                CryptoId     = cryptoId,
                FiatCurrency = fiatCurrency,
                MerchantGuid = account.Id,
                OrderNo      = NumberGenerator.GenerateUnixOrderNo(),
                CountryId    = account.CountryId,
                Markup       = account.Markup,
                Type         = paymentType,
                UserId       = Guid.Empty
            };

            Guid?userAccountId = null;

            if (!string.IsNullOrEmpty(userToken))
            {
                if (!userToken.StartsWith(Constant.PAYMENT_CODE_PREFIX))
                {
                    throw new CommonException(ReasonCode.GENERAL_ERROR, Resources.无效的用户Token);
                }

                var paymentInfo = RedisHelper.Get <PaymentCodeDTO>(
                    Constant.REDIS_PAYMENT_CODE_DBINDEX,
                    $"{Constant.REDIS_PAYMENT_CODE_PREFIX}{userToken}");
                if (paymentInfo == null)
                {
                    throw new CommonException(ReasonCode.GENERAL_ERROR, Resources.无效的用户Token);
                }
                userAccountId = paymentInfo.UserId;
            }
            if (userAccountId.HasValue)
            {
                order.UserId = userAccountId.Value;

                SendPayOrderModel model = new SendPayOrderModel();
                model.OrderNo       = order.OrderNo;
                model.UserAccountId = userAccountId.Value.ToString();

                MerchantMSMQ.PubPayOrder(model, 0);
            }
            RedisHelper.StringSet($"fiiipos:order:{ order.OrderNo}", JsonConvert.SerializeObject(order), TimeSpan.FromMinutes(30));
            return(order.OrderNo);
        }
Exemple #6
0
 private string CreateOrderno()
 {
     return(NumberGenerator.GenerateUnixOrderNo());
 }
        public void Deposit(Guid accountId, string transactionId, decimal amount, string cryptoName, DateTime timestamp, string address, string tag)
        {
            var account = _accountFactory.GetById(accountId);

            if (account == null)
            {
                throw new CommonException(20000, "Error: Invalid Account ID");
            }

            var crypto = _cryptocurrencyDac.GetByCode(cryptoName);

            if (crypto == null)
            {
                throw new CommonException(20000, "Error: Invalid Cryptocurrency");
            }

            var wallet = _walletFactory.GetByAccountId(accountId, crypto.Id);

            Deposit deposit;

            using (var scope = new TransactionScope())
            {
                if (wallet == null)
                {
                    wallet = GenerateWallet(accountId, crypto.Id, crypto.Code);
                }

                deposit = new Deposit
                {
                    AccountId     = account.Id,
                    WalletId      = wallet.Id,
                    FromAddress   = address,
                    FromTag       = tag,
                    ToAddress     = wallet.Address,
                    ToTag         = wallet.Tag,
                    Amount        = amount,
                    Status        = TransactionStatus.Confirmed,
                    Timestamp     = timestamp,
                    OrderNo       = NumberGenerator.GenerateUnixOrderNo(),
                    TransactionId = transactionId
                };
                deposit = _depositFactory.Insert(deposit);
                _walletFactory.Increase(wallet.Id, amount);
                _walletStatementFactory.Insert(new WalletStatement
                {
                    Action    = MerchantWalletStatementAction.Deposit,
                    Amount    = amount,
                    Balance   = wallet.Balance + amount,
                    Remark    = null,
                    Timestamp = DateTime.UtcNow,
                    WalletId  = wallet.Id
                });
                scope.Complete();
            }

            try
            {
                _redisMqFactory.PubDeposit(deposit.Id);

                if (!string.IsNullOrEmpty(account.Email))
                {
                    string subject = string.Format(Resources.DepositTitle, cryptoName);
                    string content = string.Format(Resources.DepositEmailContent, amount, cryptoName);
                    new EmailAgent().Send(account.Email, subject, content, 5);
                }
            }
            catch (Exception ex)
            {
                _log.Error(ex);
            }
        }
        public void DepositCompleted(Guid accountId, long depositRequestId, string cryptoName, string transactionId, decimal amount, string address, string tag)
        {
            var account = _accountFactory.GetById(accountId);

            if (account == null)
            {
                throw new CommonException(20000, "Error: Invalid Account ID");
            }

            var crypto = _cryptocurrencyDac.GetByCode(cryptoName);

            if (crypto == null)
            {
                throw new CommonException(20000, "Error: Invalid Cryptocurrency");
            }

            var deposit = _depositFactory.GetByRequestId(accountId, depositRequestId);
            var wallet  = _walletFactory.GetByAccountId(accountId, crypto.Id);

            //充值订单存在 完成订单
            if (deposit != null)
            {
                if (deposit.Status == TransactionStatus.Confirmed)
                {
                    return;
                }

                if (deposit.Status != TransactionStatus.Pending)
                {
                    throw new CommonException(20000, "Error: Invalid Deposit Status");
                }

                using (var scope = new TransactionScope())
                {
                    _walletFactory.Increase(deposit.WalletId, deposit.Amount);
                    _depositFactory.CompletedByRequestId(accountId, wallet.Id, depositRequestId);
                    _transactionFactory.UpdateStatus(UserTransactionType.Deposit, deposit.Id.ToString(), accountId, (byte)TransactionStatus.Confirmed);
                    _walletStatementFactory.Insert(new WalletStatement
                    {
                        Action        = MerchantWalletStatementAction.Deposit,
                        Amount        = amount,
                        Balance       = wallet.Balance + amount,
                        FrozenAmount  = 0,
                        FrozenBalance = wallet.FrozenBalance,
                        Remark        = null,
                        Timestamp     = DateTime.UtcNow,
                        WalletId      = wallet.Id
                    });
                    scope.Complete();
                }
            }
            //充值订单不存在 创建一条已完成订单
            else
            {
                if (string.IsNullOrEmpty(transactionId))
                {
                    throw new CommonException(20000, "Invalid TransactionId");
                }

                using (var scope = new TransactionScope())
                {
                    if (wallet == null)
                    {
                        wallet = GenerateWallet(account.Id, crypto.Id, crypto.Code);
                    }

                    deposit = _depositFactory.Insert(new Deposit
                    {
                        AccountId     = account.Id,
                        WalletId      = wallet.Id,
                        FromAddress   = address,
                        FromTag       = tag,
                        ToAddress     = wallet.Address,
                        ToTag         = wallet.Tag,
                        Amount        = amount,
                        Status        = TransactionStatus.Confirmed,
                        Timestamp     = DateTime.UtcNow,
                        OrderNo       = NumberGenerator.GenerateUnixOrderNo(),
                        TransactionId = transactionId,
                        RequestId     = depositRequestId,
                        CryptoCode    = crypto.Code,
                        FromType      = DepositFromType.Deposit
                    });
                    _transactionFactory.Insert(new UserTransaction
                    {
                        Id         = Guid.NewGuid(),
                        AccountId  = account.Id,
                        CryptoId   = crypto.Id,
                        CryptoCode = crypto.Code,
                        Type       = UserTransactionType.Deposit,
                        DetailId   = deposit.Id.ToString(),
                        Status     = (byte)deposit.Status,
                        Timestamp  = deposit.Timestamp,
                        Amount     = amount,
                        OrderNo    = deposit.OrderNo
                    });
                    _walletFactory.Increase(wallet.Id, amount);
                    _walletStatementFactory.Insert(new WalletStatement
                    {
                        Action        = MerchantWalletStatementAction.Deposit,
                        Amount        = amount,
                        Balance       = wallet.Balance + amount,
                        FrozenAmount  = 0,
                        FrozenBalance = wallet.FrozenBalance,
                        Remark        = null,
                        Timestamp     = DateTime.UtcNow,
                        WalletId      = wallet.Id
                    });
                    scope.Complete();
                }
            }
            try
            {
                _redisMqFactory.PubDeposit(deposit.Id);

                //if (!string.IsNullOrEmpty(account.Email))
                //{
                //    string subject = string.Format(Resources.DepositTitle, cryptoName);
                //    string content = string.Format(Resources.DepositEmailContent, deposit.Amount.Value, cryptoName);
                //    new EmailAgent().Send(account.Email, subject, content, 5);
                //}
            }
            catch (Exception ex)
            {
                _log.Error(ex);
            }
        }
        public void DepositPending(Guid accountId, long requestId, string transactionId, decimal amount, string cryptoName, string address, string tag)
        {
            if (string.IsNullOrEmpty(transactionId))
            {
                throw new CommonException(20000, "Invalid TransactionId");
            }

            var crypto = _cryptocurrencyDac.GetByCode(cryptoName);

            if (crypto == null)
            {
                throw new CommonException(20000, "Error: Invalid Cryptocurrency");
            }

            var account = _accountFactory.GetById(accountId);

            if (account == null)
            {
                throw new CommonException(20000, "Error: Invalid Account ID");
            }

            //防止重复处理
            var deposit = _depositFactory.GetByRequestId(accountId, requestId);

            if (deposit != null)
            {
                throw new CommonException(20000, "Error: Duplicate RequestId");
            }

            var wallet = _walletFactory.GetByAccountId(accountId, crypto.Id);

            using (var scope = new TransactionScope())
            {
                if (wallet == null)
                {
                    wallet = GenerateWallet(accountId, crypto.Id, crypto.Code);
                }

                var depositObj = _depositFactory.Insert(new Deposit
                {
                    AccountId     = account.Id,
                    WalletId      = wallet.Id,
                    FromAddress   = address,
                    FromTag       = tag,
                    ToAddress     = wallet.Address,
                    ToTag         = wallet.Tag,
                    Amount        = amount,
                    Status        = TransactionStatus.Pending,
                    Timestamp     = DateTime.UtcNow,
                    OrderNo       = NumberGenerator.GenerateUnixOrderNo(),
                    TransactionId = transactionId,
                    RequestId     = requestId,
                    CryptoCode    = crypto.Code,
                    FromType      = DepositFromType.Deposit
                });

                _transactionFactory.Insert(new UserTransaction
                {
                    Id         = Guid.NewGuid(),
                    AccountId  = account.Id,
                    CryptoId   = crypto.Id,
                    CryptoCode = crypto.Code,
                    Type       = UserTransactionType.Deposit,
                    DetailId   = depositObj.Id.ToString(),
                    Status     = (byte)depositObj.Status,
                    Timestamp  = depositObj.Timestamp,
                    Amount     = amount,
                    OrderNo    = depositObj.OrderNo
                });

                scope.Complete();
            }
        }
        //private MerchantWithdrawal WithdrawalToMerchantAccount(MerchantWallet fromWallet, MerchantWithdrawal fromWithdraw, MerchantWallet toWallet)
        //{
        //    MerchantDeposit deposit = null;
        //    using (var scope = new TransactionScope())
        //    {
        //        //提币
        //        fromWithdraw.Status = TransactionStatus.Confirmed;
        //        fromWithdraw.TransactionId = toWallet.MerchantAccountId.ToString("N");
        //        fromWithdraw.SelfPlatform = true;//平台内提币
        //        fromWithdraw = new MerchantWithdrawalDAC().Create(fromWithdraw);

        //        var fromWithdrawFee = new MerchantWithdrawalFee
        //        {
        //            Amount = fromWithdraw.Amount,
        //            Timestamp = DateTime.UtcNow,
        //            Fee = fromWithdraw.Amount * WithdrawalMasterSetting.ToMerchantHandleFeeTier,
        //            WithdrawalId = fromWithdraw.Id
        //        };
        //        new MerchantWithdrawalFeeDAC().Create(fromWithdrawFee);

        //        new MerchantWalletDAC().Decrease(fromWallet.Id, fromWithdraw.Amount);

        //        new MerchantWalletStatementDAC().Insert(new MerchantWalletStatement
        //        {
        //            WalletId = fromWallet.Id,
        //            Action = MerchantWalletStatementAction.Withdrawal,
        //            Amount = -fromWithdraw.Amount,
        //            Balance = fromWallet.Balance - fromWithdraw.Amount,
        //            Timestamp = DateTime.UtcNow
        //        });


        //        //充币
        //        var amount = fromWithdraw.Amount - fromWithdrawFee.Fee;
        //        if (amount <= 0)
        //        {
        //            throw new CommonException(ReasonCode.GENERAL_ERROR, Resources.到账数量不能为零或者负数);
        //        }

        //        deposit = new MerchantDepositDAC().Insert(new MerchantDeposit
        //        {
        //            MerchantAccountId = toWallet.MerchantAccountId,
        //            MerchantWalletId = toWallet.Id,
        //            FromAddress = fromWallet.Address,
        //            ToAddress = toWallet.Address,
        //            Amount = fromWithdraw.Amount - fromWithdrawFee.Fee,
        //            Status = TransactionStatus.Confirmed,
        //            Timestamp = DateTime.UtcNow,
        //            OrderNo = CreateOrderno(),
        //            TransactionId = fromWallet.MerchantAccountId.ToString("N"),
        //            SelfPlatform = true
        //        });
        //        new MerchantWalletDAC().Increase(toWallet.Id, amount);
        //        new MerchantWalletStatementDAC().Insert(new MerchantWalletStatement
        //        {
        //            WalletId = toWallet.Id,
        //            Action = MerchantWalletStatementAction.Deposit,
        //            Amount = amount,
        //            Balance = toWallet.Balance + amount,
        //            Timestamp = DateTime.UtcNow
        //        });


        //        scope.Complete();
        //    }

        //    var withdrawId = fromWithdraw.Id;
        //    var depositId = deposit.Id;

        //    var t1 = Task.Run(() => new FiiiPOSPushComponent().PushWithdrawCompleted(withdrawId));
        //    var t2 = Task.Run(() => new FiiiPOSPushComponent().PushDeposit(depositId));
        //    Task.WaitAll(t1, t2);

        //    return fromWithdraw;
        //}

        private MerchantWithdrawal WithdrawalToUserAccount(MerchantWallet fromWallet, MerchantWithdrawal fromWithdraw,
                                                           UserWallet toWallet, decimal fee)
        {
            UserDeposit deposit;

            using (var scope = new TransactionScope())
            {
                //提币
                fromWithdraw.Status        = TransactionStatus.Confirmed;
                fromWithdraw.TransactionId = toWallet.UserAccountId.ToString("N");
                fromWithdraw.SelfPlatform  = true;//平台内提币
                fromWithdraw = new MerchantWithdrawalDAC().Create(fromWithdraw);

                var fromWithdrawFee = new MerchantWithdrawalFee
                {
                    Amount       = fromWithdraw.Amount,
                    Timestamp    = DateTime.UtcNow,
                    Fee          = fee,
                    WithdrawalId = fromWithdraw.Id
                };
                new MerchantWithdrawalFeeDAC().Create(fromWithdrawFee);

                new MerchantWalletDAC().Decrease(fromWallet.Id, fromWithdraw.Amount);

                new MerchantWalletStatementDAC().Insert(new MerchantWalletStatement
                {
                    WalletId  = fromWallet.Id,
                    Action    = MerchantWalletStatementAction.Withdrawal,
                    Amount    = -fromWithdraw.Amount,
                    Balance   = fromWallet.Balance - fromWithdraw.Amount,
                    Timestamp = DateTime.UtcNow
                });

                //充币
                var amount = fromWithdraw.Amount - fromWithdrawFee.Fee;
                new UserWalletDAC().Increase(toWallet.Id, amount);
                new UserWalletStatementDAC().Insert(new UserWalletStatement
                {
                    WalletId      = toWallet.Id,
                    Action        = UserWalletStatementAction.Deposit,
                    Amount        = amount,
                    Balance       = toWallet.Balance + amount,
                    FrozenAmount  = 0,
                    FrozenBalance = toWallet.FrozenBalance,
                    Timestamp     = DateTime.UtcNow
                });

                deposit = new UserDepositDAC().Insert(new UserDeposit
                {
                    UserAccountId = toWallet.UserAccountId,
                    UserWalletId  = toWallet.Id,
                    FromAddress   = fromWallet.Address,
                    FromTag       = fromWallet.Tag,
                    ToAddress     = toWallet.Address,
                    ToTag         = toWallet.Tag,
                    Amount        = amount,
                    Status        = TransactionStatus.Confirmed,
                    Timestamp     = DateTime.UtcNow,
                    OrderNo       = NumberGenerator.GenerateUnixOrderNo(),
                    TransactionId = fromWallet.MerchantAccountId.ToString("N"),
                    SelfPlatform  = true,
                    CryptoCode    = toWallet.CryptoCode
                });

                new UserTransactionDAC().Insert(new UserTransaction
                {
                    Id         = Guid.NewGuid(),
                    AccountId  = toWallet.UserAccountId,
                    CryptoId   = toWallet.CryptoId,
                    CryptoCode = toWallet.CryptoCode,
                    Type       = UserTransactionType.Deposit,
                    DetailId   = deposit.Id.ToString(),
                    Status     = (byte)deposit.Status,
                    Timestamp  = deposit.Timestamp,
                    Amount     = amount,
                    OrderNo    = deposit.OrderNo
                });

                scope.Complete();
            }

            var withdrawId = fromWithdraw.Id;
            var depositId  = deposit.Id;

            MerchantMSMQ.PubMerchantWithdrawCompleted(withdrawId, 0);
            MerchantMSMQ.PubUserDeposit(depositId, 0);

            return(fromWithdraw);
        }
        public MerchantWithdrawal Withdrawal(Guid accountId, decimal amount, int cryptoId, string address, string tag, string clientIP)
        {
            SecurityVerify.Verify <WithdrawVerify>(new CustomVerifier("MerchantWithdraw"), SystemPlatform.FiiiPOS, accountId.ToString(), (model) =>
            {
                return(model.PinVerified && model.CombinedVerified);
            });

            var cryptocurrency = new CryptocurrencyDAC().GetById(cryptoId);

            CryptoAddressValidation.ValidateAddress(cryptocurrency.Code, address);

            if (!string.IsNullOrEmpty(tag))
            {
                CryptoAddressValidation.ValidateTag(cryptocurrency.Code, tag);
            }

            var account = new MerchantAccountDAC().GetById(accountId);

            if (!new ProfileComponent().ValidateLv1(accountId))
            {
                throw new CommonException(ReasonCode.NOT_VERIFY_LV1, Resources.需要Lv1认证才能使用相关功能);
            }

            if (!account.IsAllowWithdrawal)
            {
                throw new CommonException(ReasonCode.Not_Allow_Withdrawal, Resources.禁止提币);
            }

            if (!cryptocurrency.Status.HasFlag(CryptoStatus.Withdrawal))
            {
                throw new CommonException(ReasonCode.CURRENCY_FORBIDDEN, Resources.CurrencyForbidden);
            }

            if (cryptocurrency.Enable == (byte)CurrencyStatus.Forbidden)
            {
                throw new CommonException(ReasonCode.CURRENCY_FORBIDDEN, Resources.CurrencyForbidden);
            }

            var fromWallet = new MerchantWalletDAC().GetByAccountId(accountId, cryptoId);

            if (fromWallet == null)
            {
                throw new CommonException(ReasonCode.Not_Allow_Withdrawal, Resources.禁止提币);
            }

            if (fromWallet.Balance < amount)
            {
                throw new CommonException(ReasonCode.GENERAL_ERROR, Resources.余额不足);
            }

            var profileAgent = new MerchantProfileAgent();
            var profile      = profileAgent.GetMerchantProfile(accountId);

            int level = profile.L2VerifyStatus == VerifyStatus.Certified ? 2 : profile.L1VerifyStatus == VerifyStatus.Certified ? 1 : 0;

            var masterSetting = GetMerchantWithdrawalMasterSettingWithCrypto(cryptocurrency, level);

            if (amount > masterSetting.PerTxLimit)
            {
                throw new CommonException(ReasonCode.GENERAL_ERROR, Resources.能高于单次提币量);
            }
            var     dac             = new MerchantWithdrawalDAC();
            var     today           = DateTime.UtcNow.Date;
            decimal dailyWithdrawal = dac.DailyWithdrawal(accountId, cryptoId, today);

            if (amount > masterSetting.PerDayLimit - dailyWithdrawal)
            {
                throw new CommonException(ReasonCode.GENERAL_ERROR, Resources.今日提币达到限额);
            }
            decimal monthlyWithdrawal = dac.MonthlyWithdrawal(accountId, cryptoId, new DateTime(today.Year, today.Month, 1));

            if (amount > masterSetting.PerMonthLimit - monthlyWithdrawal)
            {
                throw new CommonException(ReasonCode.GENERAL_ERROR, Resources.本月提币达到限额);
            }

            var fromWithdraw = new MerchantWithdrawal
            {
                MerchantAccountId = accountId,
                MerchantWalletId  = fromWallet.Id,
                Address           = address,
                Tag        = tag,
                Amount     = amount,
                Status     = TransactionStatus.UnSubmit,
                Timestamp  = DateTime.UtcNow,
                OrderNo    = NumberGenerator.GenerateUnixOrderNo(),
                CryptoId   = fromWallet.CryptoId,
                CryptoCode = fromWallet.CryptoCode
            };

            var merchantWalletDac = new MerchantWalletDAC();
            var userWalletDac     = new UserWalletDAC();

            //是否是商户地址
            var toMerchantWallet = merchantWalletDac.GetByAddress(address, cryptocurrency.NeedTag ? tag : null);

            if (toMerchantWallet != null)
            {
                //if (toMerchantWallet.CryptoId != cryptoId)
                //    throw new CommonException(10000, string.Format(Resources.提币地址不是有效的地址, cryptocurrency.Code));
                //if (toMerchantWallet.MerchantAccountId == accountId)
                //    throw new CommonException(ReasonCode.CANNOT_TRANSFER_TO_YOURSELF, Resources.提币地址不能是自己账户的地址);
                //return WithdrawalToMerchantAccount(fromWallet, fromWithdraw, toMerchantWallet);
                // 042018
                throw new CommonException(ReasonCode.CAN_NOT_WITHDRAW_TO_FiiiPOS, Resources.FiiiPOSCantWithdrawToFiiiPOS);
            }

            //是否是用户地址
            var toUserWallet = userWalletDac.GetByAddressAndCrypto(cryptoId, address, cryptocurrency.NeedTag ? tag : null);

            if (toUserWallet != null)
            {
                if (toUserWallet.CryptoId != cryptoId)
                {
                    throw new CommonException(ReasonCode.GENERAL_ERROR, FiiiPay.Framework.Component.Properties.GeneralResources.EMInvalidAddress);
                }

                if (amount < masterSetting.ToUserMinAmount)
                {
                    throw new CommonException(10000, Resources.能低于最低提币量);
                }

                var fee = (fromWithdraw.Amount * masterSetting.ToUserHandleFeeTier).ToSpecificDecimal(cryptocurrency.DecimalPlace);
                if (amount <= fee)
                {
                    throw new CommonException(ReasonCode.GENERAL_ERROR, Resources.到账数量不能为零或者负数);
                }

                return(WithdrawalToUserAccount(fromWallet, fromWithdraw, toUserWallet, fee));
            }

            //平台内提币如果tag不对,创建一条失败记录
            if (cryptocurrency.NeedTag && (userWalletDac.IsUserWalletAddress(address) || merchantWalletDac.IsMerchantWalletAddress(address)))
            {
                return(CancelWithdrawal(fromWithdraw));
            }

            //如果都不是,提币到场外
            if (amount < masterSetting.ToOutsideMinAmount)
            {
                throw new CommonException(ReasonCode.GENERAL_ERROR, Resources.能低于最低提币量);
            }

            var baseFee  = cryptocurrency.Withdrawal_Fee ?? 0;
            var tier     = cryptocurrency.Withdrawal_Tier ?? 0;
            var fee1     = (amount * tier).ToSpecificDecimal(cryptocurrency.DecimalPlace);
            var totalFee = baseFee + fee1;

            if (amount <= totalFee)
            {
                throw new CommonException(ReasonCode.GENERAL_ERROR, Resources.到账数量不能为零或者负数);
            }

            return(WithdrawalToOutside(fromWallet, fromWithdraw, cryptocurrency, account, amount, totalFee, address, tag, clientIP));
        }