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

            //(order.ActualFiatAmount, order.CryptoAmount, order.TransactionFee, order.ActualCryptoAmount) =
            //    CalculateAmount(amount, account.Markup, account.Receivables_Tier, order.ExchangeRate, coin);
            //(order.UnifiedFiatAmount, order.UnifiedActualFiatAmount) = CalculateUnifiedAmount(order.FiatAmount, order.ActualFiatAmount, order.UnifiedExchangeRate);
            //return order;
            var calcModel =
                CalculateAmount(fiatAmount, merchantAccount.Markup, merchantAccount.Receivables_Tier, order.ExchangeRate, coin);

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

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

            order.UnifiedFiatAmount       = model.UnifiedFiatAmount;
            order.UnifiedActualFiatAmount = model.UnifiedActualFiatAmount;
            return(order);
        }
Пример #2
0
        public GatewayOrderInfoOM PrePay(string code, UserAccount account)
        {
            var codeEntity = QRCode.Deserialize(code);

            if (codeEntity.SystemPlatform != SystemPlatform.Gateway || codeEntity.QrCodeEnum != QRCodeEnum.GateWayPay)
            {
                throw new CommonException(ReasonCode.INVALID_QRCODE, MessageResources.InvalidQRCode);
            }

            var orderDetail = GetGatewayOrderDetail(codeEntity.QRCodeKey);

            if (orderDetail == null)
            {
                throw new CommonException(ReasonCode.INVALID_QRCODE, MessageResources.InvalidQRCode);
            }


            var cryptoCurrency = new CryptocurrencyDAC().GetByCode(orderDetail.Crypto);

            if (cryptoCurrency == null || cryptoCurrency?.Id == null)
            {
                throw new CommonException(ReasonCode.CRYPTO_NOT_EXISTS, "Error: Invalid Cryptocurrency");
            }

            var goDAC        = new GatewayOrderDAC();
            var gatewayOrder = goDAC.GetByTradeNo(orderDetail.Id.ToString());

            if (gatewayOrder != null)
            {
                if (gatewayOrder.Status != GatewayOrderStatus.Pending)
                {
                    throw new CommonException(ReasonCode.ORDER_HAD_COMPLETE, MessageResources.OrderComplated);
                }
            }
            else
            {
                gatewayOrder = new GatewayOrder()
                {
                    OrderNo            = IdentityHelper.OrderNo(),
                    TradeNo            = orderDetail.Id.ToString(),
                    Id                 = Guid.NewGuid(),
                    CryptoId           = cryptoCurrency.Id,
                    MerchantAccountId  = orderDetail.MerchantAccountId,
                    FiatAmount         = orderDetail.FiatAmount,
                    MerchantName       = orderDetail.MerchantName,
                    UserAccountId      = account.Id,
                    CryptoAmount       = orderDetail.CryptoAmount,
                    ActualCryptoAmount = orderDetail.ActualCryptoAmount,
                    FiatCurrency       = orderDetail.FiatCurrency,
                    Markup             = orderDetail.MarkupRate,
                    ActualFiatAmount   = orderDetail.ActualFiatAmount,
                    Status             = GatewayOrderStatus.Pending,
                    ExchangeRate       = orderDetail.ExchangeRate,
                    ExpiredTime        = orderDetail.ExpiredTime,
                    TransactionFee     = orderDetail.TransactionFee,
                    Timestamp          = DateTime.UtcNow,
                    Remark             = orderDetail.Remark
                };
                goDAC.Insert(gatewayOrder);
            }

            return(new GatewayOrderInfoOM()
            {
                Timestamp = DateTime.UtcNow.ToUnixTime().ToString(),
                OrderId = gatewayOrder.Id,
                MerchantName = gatewayOrder.MerchantName,
                CryptoCode = cryptoCurrency.Code,
                ActurlCryptoAmount = gatewayOrder.ActualCryptoAmount
            });
        }
Пример #3
0
        private WithdrawOM WithdrawalToUserAccount(UserWallet fromWallet, UserWithdrawal fromWithdraw, UserWallet toWallet)
        {
            var         mastSettings = new MasterSettingDAC().SelectByGroup("UserWithdrawal");
            UserDeposit model        = new UserDeposit();

            using (var scope = new TransactionScope(TransactionScopeOption.Required, new TimeSpan(0, 0, 1, 30)))
            {
                fromWithdraw.Status        = TransactionStatus.Confirmed;
                fromWithdraw.TransactionId = toWallet.UserAccountId.ToString("N");
                fromWithdraw.SelfPlatform  = true;//平台内提币
                fromWithdraw.Id            = new UserWithdrawalDAC().Create(fromWithdraw);

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

                var fromWithdrawFee = new UserWithdrawalFee
                {
                    Amount       = fromWithdraw.Amount,
                    WithdrawalId = fromWithdraw.Id,
                    Fee          = fromWithdraw.Amount *
                                   Convert.ToDecimal(mastSettings.First(e => e.Name == "UserWithdrawal_ToUser").Value),
                    Timestamp = DateTime.UtcNow
                };

                new UserWithdrawalFeeDAC().Create(fromWithdrawFee);

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

                new UserWalletStatementDAC().Insert(new UserWalletStatement
                {
                    WalletId      = fromWallet.Id,
                    Action        = MerchantWalletStatementAction.Withdrawal,
                    Amount        = -fromWithdraw.Amount,
                    Balance       = fromWallet.Balance - fromWithdraw.Amount,
                    FrozenAmount  = 0,
                    FrozenBalance = fromWallet.FrozenBalance,
                    Timestamp     = DateTime.UtcNow
                });

                //充币
                var amount = fromWithdraw.Amount - fromWithdrawFee.Fee;
                if (amount <= 0)
                {
                    throw new CommonException(ReasonCode.GENERAL_ERROR, MessageResources.ArrivalAmountError);
                }

                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
                });

                model = 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       = IdentityHelper.OrderNo(),
                    TransactionId = fromWallet.UserAccountId.ToString("N"),
                    SelfPlatform  = true,
                    CryptoCode    = fromWallet.CryptoCode
                });
                new UserTransactionDAC().Insert(new UserTransaction
                {
                    Id         = Guid.NewGuid(),
                    AccountId  = model.UserAccountId,
                    CryptoId   = fromWallet.CryptoId,
                    CryptoCode = fromWallet.CryptoCode,
                    Type       = UserTransactionType.Deposit,
                    DetailId   = model.Id.ToString(),
                    Status     = (byte)model.Status,
                    Timestamp  = model.Timestamp,
                    Amount     = model.Amount,
                    OrderNo    = model.OrderNo
                });

                scope.Complete();
            }

            UserMSMQ.PubUserWithdrawCompleted(fromWithdraw.Id, 0);
            UserMSMQ.PubUserDeposit(model.Id, 0);

            return(new WithdrawOM
            {
                OrderId = fromWithdraw.Id,
                OrderNo = fromWithdraw.OrderNo,
                Timestamp = fromWithdraw.Timestamp.ToUnixTime().ToString()
            });
        }
Пример #4
0
        public WithdrawOM Withdraw(UserAccount user, WithdrawIM im, string clientIP)
        {
            SecurityVerify.Verify <WithdrawVerify>(new CustomVerifier("UserWithdraw"), SystemPlatform.FiiiPay, user.Id.ToString(), (model) =>
            {
                return(model.PinVerified && model.CombinedVerified);
            });


            if (user.L1VerifyStatus != VerifyStatus.Certified)
            {
                throw new CommonException(ReasonCode.NOT_VERIFY_LV1, Resources.EMNeedLV1Verfied);
            }

            var cryptocurrency = new CryptocurrencyDAC().GetById(im.CoinId);

            if (!cryptocurrency.Status.HasFlag(CryptoStatus.Withdrawal) || cryptocurrency.Enable == 0)
            {
                throw new CommonException(ReasonCode.CURRENCY_FORBIDDEN, MessageResources.CurrencyForbidden);
            }

            CryptoAddressValidation.ValidateAddress(cryptocurrency.Code, im.Address);
            if (!string.IsNullOrEmpty(im.Tag))
            {
                CryptoAddressValidation.ValidateTag(cryptocurrency.Code, im.Tag);
            }
            //else if (cryptocurrency.NeedTag)
            //{
            //    throw new CommonException(ReasonCode.NEED_INPUT_TAG, GeneralResources.EMNeedInputTag);
            //}

            if (im.Amount <= 0)
            {
                throw new ApplicationException(MessageResources.AmountGreater);
            }

            var IsAllowWithdrawal = user.IsAllowWithdrawal ?? true;

            if (!IsAllowWithdrawal)
            {
                throw new CommonException(ReasonCode.Not_Allow_Withdrawal, MessageResources.WithdrawalDisabled);
            }

            var fromWallet = new UserWalletDAC().GetByAccountId(user.Id, im.CoinId);


            //var profile = new UserProfileAgent().GetUserProfile(user.Id);

            //标准化这个金额,防止超过8位
            im.Amount = im.Amount.ToSpecificDecimal(cryptocurrency.DecimalPlace);

            var mastSettings = new MasterSettingDAC().SelectByGroup("UserWithdrawal");

            var Withdrawal_PerTx_Limit_User_NotVerified    = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerTx_Limit_User_NotVerified").Value);
            var Withdrawal_PerDay_Limit_User_NotVerified   = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerDay_Limit_User_NotVerified").Value);
            var Withdrawal_PerMonth_Limit_User_NotVerified = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerMonth_Limit_User_NotVerified").Value);

            var Withdrawal_PerTx_Limit_User_Lv1Verified    = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerTx_Limit_User_Lv1Verified").Value);
            var Withdrawal_PerDay_Limit_User_Lv1Verified   = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerDay_Limit_User_Lv1Verified").Value);
            var Withdrawal_PerMonth_Limit_User_Lv1Verified = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerMonth_Limit_User_Lv1Verified").Value);

            var Withdrawal_PerTx_Limit_User_Lv2Verified    = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerTx_Limit_User_Lv2Verified").Value);
            var Withdrawal_PerDay_Limit_User_Lv2Verified   = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerDay_Limit_User_Lv2Verified").Value);
            var Withdrawal_PerMonth_Limit_User_Lv2Verified = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_PerMonth_Limit_User_Lv2Verified").Value);

            var MinAmount = Convert.ToDecimal(mastSettings.First(e => e.Name == "Withdrawal_MinAmount").Value);

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

            var isWithdrawToInside = (merchantWalletDac.IsMerchantWalletAddress(im.Address) || userWalletDac.IsUserWalletAddress(im.Address));

            if (isWithdrawToInside)
            {
                MinAmount = Convert.ToDecimal(mastSettings.First(e => e.Name == "UserWithdrawal_ToUser_MinAmount").Value);
            }

            var exchangeRate = GetMarketPrice(user.CountryId, cryptocurrency.Code, "USD");

            var _minAmount = (MinAmount / exchangeRate).ToSpecificDecimal(cryptocurrency.DecimalPlace);

            if (im.Amount < _minAmount)
            {
                throw new ApplicationException(MessageResources.MinWidrawalError);
            }

            var     withdrawalDAC     = new UserWithdrawalDAC();
            var     today             = DateTime.UtcNow.Date;
            decimal dailyWithdrawal   = withdrawalDAC.DailyWithdrawal(user.Id, im.CoinId, today);
            decimal monthlyWithdrawal = withdrawalDAC.MonthlyWithdrawal(user.Id, im.CoinId, new DateTime(today.Year, today.Month, 1));

            var PerDayLimit   = 0M;
            var PerMonthLimit = 0M;

            if (user.L1VerifyStatus == VerifyStatus.Certified && user.L2VerifyStatus == VerifyStatus.Certified)
            {
                PerDayLimit   = Withdrawal_PerDay_Limit_User_Lv2Verified;
                PerMonthLimit = Withdrawal_PerMonth_Limit_User_Lv2Verified;
            }
            else if (user.L1VerifyStatus == VerifyStatus.Certified && user.L2VerifyStatus != VerifyStatus.Certified)
            {
                PerDayLimit   = Withdrawal_PerDay_Limit_User_Lv1Verified;
                PerMonthLimit = Withdrawal_PerMonth_Limit_User_Lv1Verified;
            }
            else if (user.L1VerifyStatus != VerifyStatus.Certified && user.L2VerifyStatus != VerifyStatus.Certified)
            {
                PerDayLimit   = Withdrawal_PerDay_Limit_User_NotVerified;
                PerMonthLimit = Withdrawal_PerMonth_Limit_User_NotVerified;
            }
            if ((PerDayLimit / exchangeRate - dailyWithdrawal).ToSpecificDecimal(cryptocurrency.DecimalPlace) < im.Amount)
            {
                throw new ApplicationException(MessageResources.TodayWidrawalLimit);
            }
            if ((PerMonthLimit / exchangeRate - monthlyWithdrawal).ToSpecificDecimal(cryptocurrency.DecimalPlace) < im.Amount)
            {
                throw new ApplicationException(MessageResources.MonthWithdrawalLimit);
            }

            var fromWithdraw = new UserWithdrawal
            {
                UserAccountId = user.Id,
                UserWalletId  = fromWallet.Id,
                Address       = im.Address,
                Tag           = im.Tag,
                Amount        = im.Amount,
                Status        = TransactionStatus.UnSubmit,
                Timestamp     = DateTime.UtcNow,
                OrderNo       = IdentityHelper.OrderNo(),
                CryptoCode    = fromWallet.CryptoCode,
                CryptoId      = fromWallet.CryptoId
            };

            //是否是商户地址
            var toMerchantWallet = merchantWalletDac.GetByAddressAndCrypto(im.CoinId, im.Address, im.Tag);

            if (toMerchantWallet != null)
            {
                //if (toMerchantWallet.CryptoId != im.CoinId)
                //    throw new CommonException(ReasonCode.GENERAL_ERROR, GeneralResources.EMInvalidAddress);
                //return WithdrawalToMerchantAccount(fromWallet, fromWithdraw, fromWithdrawFee, toMerchantWallet, cryptocurrency);
                //042018
                throw new CommonException(ReasonCode.CAN_NOT_WITHDRAW_TO_FiiiPOS, MessageResources.FiiiPayCantWithdrawToFiiiPOS);
            }

            //是否是用户地址
            var toUserWallet = userWalletDac.GetByAddressAndCrypto(im.CoinId, im.Address, im.Tag);

            if (toUserWallet != null)
            {
                if (toUserWallet.UserAccountId == user.Id)
                {
                    throw new CommonException(ReasonCode.CANNOT_TRANSFER_TO_YOURSELF, MessageResources.WithdrawalToSelfError);
                }

                var toFiiiPayMinWithdrawAmount = GetToFiiiPayMinAmount(Convert.ToDecimal(mastSettings.First(e => e.Name == "UserWithdrawal_ToUser_MinAmount").Value), exchangeRate, cryptocurrency.DecimalPlace);
                if (im.Amount < toFiiiPayMinWithdrawAmount)
                {
                    throw new CommonException(10000, MessageResources.MinWidrawalError);
                }

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

            var tier = cryptocurrency.Withdrawal_Tier ?? 0;
            var fee  = im.Amount * tier + (cryptocurrency.Withdrawal_Fee ?? 0);

            fee = fee.ToSpecificDecimal(cryptocurrency.DecimalPlace);
            var actualAmount = im.Amount - fee;

            if (fromWallet.Balance < im.Amount)
            {
                throw new CommonException(ReasonCode.INSUFFICIENT_BALANCE, MessageResources.InsufficientBalance);
            }
            if (actualAmount <= 0)
            {
                throw new CommonException(ReasonCode.GENERAL_ERROR, MessageResources.ArrivalAmountError);
            }

            //地址是FiiiPay的地址,但tag找不到
            if (cryptocurrency.NeedTag && isWithdrawToInside)
            {
                return(CancelWithdrawal(fromWithdraw));
            }

            ILog _logger = LogManager.GetLogger("LogicError");

            //如果都不是,向Finance申请提现

            //var agent = new FiiiFinanceAgent();

            var requestModel = new CreateWithdrawModel
            {
                AccountID        = user.Id,
                AccountType      = AccountTypeEnum.User,
                CryptoName       = cryptocurrency.Code,
                ReceivingAddress = im.Address,
                DestinationTag   = im.Tag,
                Amount           = actualAmount,
                IPAddress        = clientIP,
                TransactionFee   = fee
            };

            using (var scope = new TransactionScope())
            {
                try
                {
                    fromWithdraw.Id = withdrawalDAC.Create(fromWithdraw);
                    var fromWithdrawFee = new UserWithdrawalFee
                    {
                        Amount       = im.Amount,
                        Fee          = fee,
                        Timestamp    = DateTime.UtcNow,
                        WithdrawalId = fromWithdraw.Id
                    };

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

                    new UserWithdrawalFeeDAC().Create(fromWithdrawFee);

                    userWalletDac.Freeze(fromWallet.Id, im.Amount);

                    new UserWalletStatementDAC().Insert(new UserWalletStatement
                    {
                        WalletId      = fromWallet.Id,
                        Action        = UserWalletStatementAction.Withdrawal,
                        Amount        = 0 - im.Amount,
                        Balance       = fromWallet.Balance - im.Amount,
                        FrozenAmount  = im.Amount,
                        FrozenBalance = fromWallet.FrozenBalance + im.Amount,
                        Timestamp     = DateTime.UtcNow
                    });

                    requestModel.WithdrawalId = fromWithdraw.Id;
                    Framework.Queue.RabbitMQSender.SendMessage("WithdrawSubmit", requestModel);

                    scope.Complete();
                }
                catch (CommonException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    _logger.Info($"Withdraw CreateWithdrawRequest faild.WithdrawID:{fromWithdraw.Id},OrderNo:{fromWithdraw.OrderNo}.request Parameter - {requestModel}. Error message:{ex.Message}");
                    throw;
                }
            }

            return(new WithdrawOM
            {
                OrderId = fromWithdraw.Id,
                OrderNo = fromWithdraw.OrderNo,
                Timestamp = fromWithdraw.Timestamp.ToUnixTime().ToString()
            });
        }
Пример #5
0
        /// <summary>
        /// 用户主动支付
        /// </summary>
        /// <param name="user"></param>
        /// <param name="im"></param>
        /// <returns></returns>
        public PayOrderOM Pay(UserAccount user, PayIM im)
        {
            if (im.Amount <= 0)
            {
                throw new CommonException(ReasonCode.GENERAL_ERROR, MessageResources.AmountGreater);
            }

            new SecurityComponent().VerifyPin(user, im.Pin);

            var isAllowExpense = user.IsAllowExpense ?? true;

            if (!isAllowExpense)
            {
                throw new CommonException(ReasonCode.Not_Allow_Expense, MessageResources.PaymentForbidden);
            }

            var coin = new CryptocurrencyDAC().GetById(im.CoinId);

            if (!coin.Status.HasFlag(CryptoStatus.Pay) || coin.Enable == 0)
            {
                throw new CommonException(ReasonCode.CURRENCY_FORBIDDEN, MessageResources.CurrencyForbidden);
            }

            var merchantAccount = GetMerchantAccountByIdOrCode(im.MerchantId, im.MerchantCode);

            if (merchantAccount == null)
            {
                throw new CommonException(ReasonCode.INVALID_QRCODE, MessageResources.InvalidQRCode);
            }

            if (!merchantAccount.IsAllowAcceptPayment || merchantAccount.Status == AccountStatus.Locked)
            {
                throw new CommonException(ReasonCode.Not_Allow_AcceptPayment, MessageResources.MerchantExceptionTransClose);
            }

            var country = new CountryComponent().GetById(merchantAccount.CountryId);

            var orderData = new Order
            {
                Id                  = Guid.NewGuid(),
                OrderNo             = IdentityHelper.OrderNo(),
                MerchantAccountId   = merchantAccount.Id,
                CryptoId            = coin.Id,
                CryptoCode          = coin.Code,
                FiatAmount          = im.Amount,
                PaymentType         = im.PaymentType,
                FiatCurrency        = merchantAccount.FiatCurrency,
                Status              = OrderStatus.Completed,
                ExpiredTime         = DateTime.UtcNow.AddMinutes(30),
                Markup              = merchantAccount.Markup,
                ExchangeRate        = GetExchangeRate(merchantAccount.CountryId, merchantAccount.FiatCurrency, coin),
                UnifiedExchangeRate = GetExchangeRate(merchantAccount.CountryId, country.FiatCurrency ?? "USD", coin),
                UnifiedFiatCurrency = country.FiatCurrency ?? "USD",
                MerchantIP          = null,
                PaymentTime         = DateTime.UtcNow,
                UserAccountId       = user.Id,
                Timestamp           = DateTime.UtcNow
            };

            var order = Generate(merchantAccount, coin, country.FiatCurrency ?? "USD", im.Amount, im.PaymentType);

            order.UserAccountId = user.Id;

            var userWallet = new UserWalletDAC().GetByAccountId(user.Id, im.CoinId);

            if (userWallet.Balance < order.CryptoAmount)
            {
                throw new CommonException(ReasonCode.INSUFFICIENT_BALANCE, MessageResources.InsufficientBalance);
            }

            order.Status      = OrderStatus.Completed;
            order.PaymentTime = DateTime.UtcNow;

            var merchantWallet = new MerchantWalletDAC().GetByAccountId(order.MerchantAccountId, order.CryptoId);

            if (merchantWallet == null || !merchantWallet.SupportReceipt)
            {
                throw new ApplicationException(MessageResources.MerchantNotSupperCrypto);
            }

            if (merchantAccount.WithdrawalFeeType != WithdrawalFeeType.FiiiCoin)
            {
                var calcModel =
                    CalculateAmount(im.Amount, merchantAccount.Markup, merchantAccount.Receivables_Tier, orderData.ExchangeRate, coin);

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

                var model = CalculateUnifiedAmount(orderData.CryptoAmount, orderData.ActualCryptoAmount, orderData.UnifiedExchangeRate);
                orderData.UnifiedFiatAmount       = model.UnifiedFiatAmount;
                orderData.UnifiedActualFiatAmount = model.UnifiedActualFiatAmount;
                var orderWithdrawalFee = new OrderWithdrawalFee
                {
                    Timestamp = DateTime.UtcNow,
                    CryptoId  = orderData.CryptoId,
                    Amount    = 0
                };

                Execute(orderWithdrawalFee);
            }
            else
            {
                var orderWithdrawalFee = CalculateOrderAmount(ref orderData, new RedisOrderDTO()
                {
                    CountryId = merchantAccount.CountryId, FiatAmount = im.Amount
                }, merchantAccount, coin);
                var wallet = new MerchantWalletDAC().GetByAccountId(merchantAccount.Id, new CryptocurrencyDAC().GetByCode("FIII").Id);
                if (orderWithdrawalFee.Amount != 0)
                {
                    using (var scope = new TransactionScope())
                    {
                        var dbOrder = new OrderDAC().Create(orderData);
                        new UserTransactionDAC().Insert(new UserTransaction
                        {
                            Id           = Guid.NewGuid(),
                            AccountId    = userWallet.UserAccountId,
                            CryptoId     = userWallet.CryptoId,
                            CryptoCode   = userWallet.CryptoCode,
                            Type         = UserTransactionType.Order,
                            DetailId     = dbOrder.Id.ToString(),
                            Status       = (byte)dbOrder.Status,
                            Timestamp    = dbOrder.Timestamp,
                            Amount       = dbOrder.CryptoAmount,
                            OrderNo      = dbOrder.OrderNo,
                            MerchantName = merchantAccount.MerchantName
                        });
                        orderWithdrawalFee.OrderId = dbOrder.Id;
                        var id = new OrderWithdrawalFeeDAC().Insert(orderWithdrawalFee);

                        new MerchantWalletDAC().Decrease(wallet.Id, orderWithdrawalFee.Amount);
                        new MerchantWalletDAC().Increase(merchantWallet.Id, orderData.ActualCryptoAmount);
                        new UserWalletDAC().Decrease(userWallet.Id, orderData.ActualCryptoAmount);
                        new UserWalletStatementDAC().Insert(new UserWalletStatement
                        {
                            Action        = UserWalletStatementAction.Consume,
                            Amount        = orderData.CryptoAmount,
                            Balance       = userWallet.Balance - orderData.CryptoAmount,
                            FrozenAmount  = 0,
                            FrozenBalance = userWallet.FrozenBalance,
                            Remark        = null,
                            Timestamp     = DateTime.UtcNow,
                            WalletId      = userWallet.Id
                        });
                        new MerchantWalletStatementDAC().Insert(new MerchantWalletStatement
                        {
                            Action    = MerchantWalletStatementAction.Receipt,
                            Amount    = orderData.ActualCryptoAmount,
                            Balance   = merchantWallet.Balance + orderData.ActualCryptoAmount,
                            Remark    = null,
                            Timestamp = DateTime.UtcNow,
                            WalletId  = merchantWallet.Id
                        });
                        new MerchantWalletStatementDAC().Insert(new MerchantWalletStatement
                        {
                            Action    = MerchantWalletStatementAction.Withdrawal,
                            Amount    = orderWithdrawalFee.Amount,
                            Balance   = merchantWallet.Balance - orderData.ActualCryptoAmount,
                            Remark    = null,
                            Timestamp = DateTime.UtcNow,
                            WalletId  = wallet.Id
                        });
                        scope.Complete();
                    }
                }
                else
                {
                    Execute(orderWithdrawalFee);
                }
            }
            void Execute(OrderWithdrawalFee orderWithdrawalFee)
            {
                using (var scope = new TransactionScope())
                {
                    var dbOrder = new OrderDAC().Create(orderData);
                    new UserTransactionDAC().Insert(new UserTransaction
                    {
                        Id           = Guid.NewGuid(),
                        AccountId    = userWallet.UserAccountId,
                        CryptoId     = userWallet.CryptoId,
                        CryptoCode   = userWallet.CryptoCode,
                        Type         = UserTransactionType.Order,
                        DetailId     = dbOrder.Id.ToString(),
                        Status       = (byte)dbOrder.Status,
                        Timestamp    = dbOrder.Timestamp,
                        Amount       = dbOrder.CryptoAmount,
                        OrderNo      = dbOrder.OrderNo,
                        MerchantName = merchantAccount.MerchantName
                    });
                    orderWithdrawalFee.OrderId = dbOrder.Id;
                    var id = new OrderWithdrawalFeeDAC().Insert(orderWithdrawalFee);

                    new UserWalletDAC().Decrease(userWallet.Id, orderData.CryptoAmount);
                    new MerchantWalletDAC().Increase(merchantWallet.Id, orderData.ActualCryptoAmount);
                    new UserWalletStatementDAC().Insert(new UserWalletStatement
                    {
                        Action        = UserWalletStatementAction.Consume,
                        Amount        = orderData.CryptoAmount,
                        Balance       = userWallet.Balance - orderData.CryptoAmount,
                        FrozenAmount  = 0,
                        FrozenBalance = userWallet.FrozenBalance,
                        Remark        = null,
                        Timestamp     = DateTime.UtcNow,
                        WalletId      = userWallet.Id
                    });
                    new MerchantWalletStatementDAC().Insert(new MerchantWalletStatement
                    {
                        Action    = MerchantWalletStatementAction.Receipt,
                        Amount    = orderData.ActualCryptoAmount,
                        Balance   = merchantWallet.Balance + orderData.ActualCryptoAmount,
                        Remark    = null,
                        Timestamp = DateTime.UtcNow,
                        WalletId  = merchantWallet.Id
                    });
                    scope.Complete();
                }
            }

            UserMSMQ.PubOrderPayed(orderData.Id, 0);
            //PushConsume(order.Id);
            UserMSMQ.PubConsumeOrder(orderData.Id);

            return(new PayOrderOM
            {
                Amount = orderData.CryptoAmount.ToString(coin.DecimalPlace),
                Currency = new CryptocurrencyDAC().GetById(order.CryptoId).Code,
                OrderId = orderData.Id.ToString(),
                OrderNo = orderData.OrderNo,
                Timestamp = orderData.PaymentTime?.ToUnixTime().ToString()
            });
        }
Пример #6
0
        public async Task <PayOrderOM> PayAsync(UserAccount user, StoreOrderPayIM im)
        {
            #region 验证
            if (im.FiatAmount <= 0)
            {
                throw new ApplicationException();
            }
            SecurityVerify.Verify(new PinVerifier(), SystemPlatform.FiiiPay, user.Id.ToString(), user.Pin, im.Pin);
            if (!user.IsAllowExpense.HasValue || !user.IsAllowExpense.Value)
            {
                throw new CommonException(ReasonCode.Not_Allow_Expense, MessageResources.PaymentForbidden);
            }

            var coin = new CryptocurrencyDAC().GetById(im.CoinId);
            if (!coin.Status.HasFlag(CryptoStatus.Pay) || coin.Enable == 0)
            {
                throw new CommonException(ReasonCode.CURRENCY_FORBIDDEN, MessageResources.CurrencyForbidden);
            }

            var merchantInfo = new MerchantInformationDAC().GetById(im.MerchantInfoId);
            if (merchantInfo.Status != Status.Enabled || merchantInfo.VerifyStatus != VerifyStatus.Certified || merchantInfo.IsPublic != Status.Enabled)
            {
                throw new CommonException(ReasonCode.Not_Allow_AcceptPayment, MessageResources.MerchantExceptionTransClose);
            }
            if (!merchantInfo.IsAllowExpense)
            {
                throw new CommonException(ReasonCode.Not_Allow_AcceptPayment, MessageResources.MerchantReceiveNotAllowed);
            }
            if (merchantInfo.AccountType == AccountType.Merchant)
            {
                throw new ApplicationException();
            }

            var storeAccount = new UserAccountDAC().GetById(merchantInfo.MerchantAccountId);
            if (storeAccount.Id == user.Id)
            {
                throw new CommonException(ReasonCode.Not_Allow_AcceptPayment, MessageResources.PaytoSelf);
            }
            if (storeAccount == null || storeAccount.Status.Value != (byte)AccountStatus.Active)
            {
                throw new CommonException(ReasonCode.Not_Allow_AcceptPayment, MessageResources.MerchantFiiipayAbnormal);
            }

            var paySetting = await new StorePaySettingDAC().GetByCountryIdAsync(merchantInfo.CountryId);
            if (paySetting != null)
            {
                if (im.FiatAmount > paySetting.LimitAmount)
                {
                    throw new CommonException(ReasonCode.TRANSFER_AMOUNT_OVERFLOW, string.Format(MessageResources.TransferAmountOverflow, paySetting.LimitAmount, paySetting.FiatCurrency));
                }
            }
            #endregion

            var walletDAC     = new UserWalletDAC();
            var statementDAC  = new UserWalletStatementDAC();
            var storeOrderDAC = new StoreOrderDAC();
            var utDAC         = new UserTransactionDAC();

            #region 计算
            decimal markup       = merchantInfo.Markup;
            decimal feeRate      = merchantInfo.FeeRate;
            var     exchangeRate = new PriceInfoDAC().GetPriceByName(storeAccount.FiatCurrency, coin.Code);

            decimal failTotalAmount    = im.FiatAmount + (im.FiatAmount * markup).ToSpecificDecimal(4);
            decimal transactionFiatFee = (im.FiatAmount * feeRate).ToSpecificDecimal(4);
            decimal transactionFee     = (transactionFiatFee / exchangeRate).ToSpecificDecimal(coin.DecimalPlace);
            decimal cryptoAmount       = (failTotalAmount / exchangeRate).ToSpecificDecimal(coin.DecimalPlace);

            var fromWallet = walletDAC.GetUserWallet(user.Id, im.CoinId);
            if (fromWallet == null || fromWallet.Balance < cryptoAmount)
            {
                throw new CommonException(ReasonCode.INSUFFICIENT_BALANCE, MessageResources.InsufficientBalance);
            }

            var toWallet = walletDAC.GetUserWallet(storeAccount.Id, im.CoinId);
            if (toWallet == null)
            {
                toWallet = new UserWalletComponent().GenerateWallet(storeAccount.Id, im.CoinId);
            }
            #endregion

            #region entity
            DateTime   dtNow = DateTime.UtcNow;
            StoreOrder order = new StoreOrder
            {
                Id                 = Guid.NewGuid(),
                OrderNo            = IdentityHelper.OrderNo(),
                Timestamp          = dtNow,
                Status             = OrderStatus.Completed,
                MerchantInfoId     = merchantInfo.Id,
                MerchantInfoName   = merchantInfo.MerchantName,
                UserAccountId      = user.Id,
                CryptoId           = im.CoinId,
                CryptoCode         = coin.Code,
                CryptoAmount       = cryptoAmount,
                CryptoActualAmount = cryptoAmount - transactionFee,
                ExchangeRate       = exchangeRate,
                Markup             = markup,
                FiatCurrency       = storeAccount.FiatCurrency,
                FiatAmount         = im.FiatAmount,
                FiatActualAmount   = failTotalAmount,
                FeeRate            = feeRate,
                TransactionFee     = transactionFee,
                PaymentTime        = dtNow
            };
            UserWalletStatement fromStatement = new UserWalletStatement
            {
                WalletId      = fromWallet.Id,
                Action        = UserWalletStatementAction.StoreOrderOut,
                Amount        = -order.CryptoAmount,
                Balance       = fromWallet.Balance - order.CryptoAmount,
                FrozenAmount  = 0,
                FrozenBalance = fromWallet.FrozenBalance,
                Timestamp     = dtNow
            };
            UserWalletStatement toStatement = new UserWalletStatement
            {
                WalletId      = toWallet.Id,
                Action        = UserWalletStatementAction.StoreOrderIn,
                Amount        = order.CryptoActualAmount,
                Balance       = toWallet.Balance + order.CryptoActualAmount,
                FrozenAmount  = 0,
                FrozenBalance = toWallet.FrozenBalance,
                Timestamp     = dtNow
            };
            #endregion

            using (var scope = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
                await storeOrderDAC.CreateAsync(order);

                await utDAC.InsertAsync(new UserTransaction
                {
                    Id           = Guid.NewGuid(),
                    AccountId    = fromWallet.UserAccountId,
                    CryptoId     = order.CryptoId,
                    CryptoCode   = order.CryptoCode,
                    Type         = UserTransactionType.StoreOrderConsume,
                    DetailId     = order.Id.ToString(),
                    Status       = (byte)order.Status,
                    Timestamp    = order.PaymentTime.Value,
                    Amount       = order.CryptoAmount,
                    OrderNo      = order.OrderNo,
                    MerchantName = order.MerchantInfoName
                });

                await utDAC.InsertAsync(new UserTransaction
                {
                    Id           = Guid.NewGuid(),
                    AccountId    = toWallet.UserAccountId,
                    CryptoId     = order.CryptoId,
                    CryptoCode   = order.CryptoCode,
                    Type         = UserTransactionType.StoreOrderIncome,
                    DetailId     = order.Id.ToString(),
                    Status       = (byte)order.Status,
                    Timestamp    = order.Timestamp,
                    Amount       = order.CryptoActualAmount,
                    OrderNo      = order.OrderNo,
                    MerchantName = order.MerchantInfoName
                });

                walletDAC.Decrease(fromWallet.Id, order.CryptoAmount);
                walletDAC.Increase(toWallet.Id, order.CryptoActualAmount);
                statementDAC.Insert(fromStatement);
                statementDAC.Insert(toStatement);
                scope.Complete();
            }

            var pushObj = new { order.Id, order.UserAccountId, order.CryptoCode };

            RabbitMQSender.SendMessage("StoreOrderPayed", new { order.Id, MerchantInfoId = merchantInfo.MerchantAccountId, order.UserAccountId, order.CryptoCode });

            return(new PayOrderOM
            {
                Amount = order.CryptoAmount.ToString(coin.DecimalPlace),
                Currency = coin.Code,
                OrderId = order.Id.ToString(),
                OrderNo = order.OrderNo,
                Timestamp = dtNow.ToUnixTime().ToString()
            });
        }