コード例 #1
0
        public static void FillOperationDetails(PayPalExpressCheckoutOperation operation, Practice practice, AccountContract contractInfo, Billing billing)
        {
            operation.DefaultCurrencyCode = CurrencyCode.Brazilian_Real;
            operation.PaymentRequests = new PayPalList<PayPalPaymentRequest>
            {
                new PayPalPaymentRequest
                {
                    BillingAgreementDescription = "O Cerebello é um software de gerênciamento de consultórios e clínicas médicas.",
                    //BillingType = BillingCode.RecurringPayments,
                    Description = "Cerebello - Plano profissional",
                    InvoiceNum = string.Format("{3}{2}:{0}.{1}", billing.IdentitySetName, billing.IdentitySetNumber, practice.Id, DebugConfig.PayPal.InvoiceIdPrefix),
                    Items = new PayPalList<PayPalPaymentRequestItem>
                    {
                        new PayPalPaymentRequestItem
                        {
                            Amount = contractInfo.BillingAmount,
                            Name = "Cerebello SaaS",
                            Description = "Software de gerenciamento de consultório médico.",
                            Category = ItemCategory.Digital,
                        },
                    },
                },
            };

            if (contractInfo.BillingDiscountAmount > 0)
            {
                operation.PaymentRequests[0].Items.Add(new PayPalPaymentRequestItem
                    {
                        Amount = -contractInfo.BillingDiscountAmount,
                        Name = "Desconto",
                        Category = ItemCategory.Digital,
                    });
            }
        }
コード例 #2
0
 /// <summary>
 /// Create a new Billing object.
 /// </summary>
 /// <param name="id">Initial value of the Id property.</param>
 /// <param name="practiceId">Initial value of the PracticeId property.</param>
 /// <param name="issuanceDate">Initial value of the IssuanceDate property.</param>
 /// <param name="dueDate">Initial value of the DueDate property.</param>
 /// <param name="afterDueTax">Initial value of the AfterDueTax property.</param>
 /// <param name="afterDueMonthlyTax">Initial value of the AfterDueMonthlyTax property.</param>
 /// <param name="isPayd">Initial value of the IsPayd property.</param>
 /// <param name="identitySetName">Initial value of the IdentitySetName property.</param>
 /// <param name="identitySetNumber">Initial value of the IdentitySetNumber property.</param>
 /// <param name="mainAmount">Initial value of the MainAmount property.</param>
 /// <param name="mainDiscount">Initial value of the MainDiscount property.</param>
 /// <param name="mainAccountContractId">Initial value of the MainAccountContractId property.</param>
 public static Billing CreateBilling(global::System.Int32 id, global::System.Int32 practiceId, global::System.DateTime issuanceDate, global::System.DateTime dueDate, global::System.Decimal afterDueTax, global::System.Decimal afterDueMonthlyTax, global::System.Boolean isPayd, global::System.String identitySetName, global::System.Int32 identitySetNumber, global::System.Decimal mainAmount, global::System.Decimal mainDiscount, global::System.Int32 mainAccountContractId)
 {
     Billing billing = new Billing();
     billing.Id = id;
     billing.PracticeId = practiceId;
     billing.IssuanceDate = issuanceDate;
     billing.DueDate = dueDate;
     billing.AfterDueTax = afterDueTax;
     billing.AfterDueMonthlyTax = afterDueMonthlyTax;
     billing.IsPayd = isPayd;
     billing.IdentitySetName = identitySetName;
     billing.IdentitySetNumber = identitySetNumber;
     billing.MainAmount = mainAmount;
     billing.MainDiscount = mainDiscount;
     billing.MainAccountContractId = mainAccountContractId;
     return billing;
 }
コード例 #3
0
 /// <summary>
 /// Deprecated Method for adding a new object to the Billings EntitySet. Consider using the .Add method of the associated ObjectSet&lt;T&gt; property instead.
 /// </summary>
 public void AddToBillings(Billing billing)
 {
     base.AddObject("Billings", billing);
 }
コード例 #4
0
        public ActionResult GenerateInvoice(GenerateInvoiceViewModel viewModel)
        {
            if (viewModel.Step == null)
            {
                if (string.IsNullOrEmpty(viewModel.PracticeIdentifier))
                {
                    this.ModelState.Clear();
                    viewModel.Step = 0;
                    return this.View();
                }

                viewModel.Step =
                    string.IsNullOrEmpty(viewModel.InvoiceName)
                    ? 1
                    : 2;
            }

            var step = viewModel.Step ?? 0;

            using (var db = this.CreateNewCerebelloEntities())
            {
                // Getting the practice indicated in the view-model.
                Practice practice = null;
                if (!string.IsNullOrWhiteSpace(viewModel.PracticeIdentifier))
                {
                    practice = db.Practices
                        .SingleOrDefault(p => p.UrlIdentifier == viewModel.PracticeIdentifier);
                }

                if (practice == null
                    || practice.ActiveAccountContractId == null
                    || practice.AccountContract.IsTrial
                    || this.ModelState.HasPropertyErrors(() => viewModel.PracticeIdentifier))
                {
                    if (practice == null)
                        this.ModelState.AddModelError(() => viewModel.PracticeIdentifier, "Consultório inexistente.");

                    if (practice != null && practice.ActiveAccountContractId == null)
                        this.ModelState.AddModelError(() => viewModel.PracticeIdentifier, "Consultório não possui uma conta ativa.");

                    if (practice != null && practice.AccountContract.IsTrial)
                        this.ModelState.AddModelError(() => viewModel.PracticeIdentifier, "Consultório possui conta trial.");

                    return this.View(viewModel);
                }

                var utcNow = this.GetUtcNow();
                viewModel.Invoices = GetAccountInvoices(practice, utcNow);

                if (step == 0)
                {
                    if (this.Request.HttpMethod == "POST")
                        return this.RedirectToAction("GenerateInvoice", new { viewModel.PracticeIdentifier });

                    // going to the next step
                    this.ModelState.Clear();
                    viewModel.Step = 1;
                    return this.View(viewModel);
                }

                var localNow = PracticeController.ConvertToLocalDateTime(practice, utcNow);

                if (step == 1)
                {
                    this.ModelState.Clear();
                    viewModel.Step = 1;
                    return this.View(viewModel);
                }

                var selectedInvoiceInfo = viewModel.Invoices.SingleOrDefault(bi => bi.NameId == viewModel.InvoiceName);

                if (selectedInvoiceInfo == null)
                {
                    this.ModelState.AddModelError(() => viewModel.InvoiceName, "Nome de invoice não encontrado.");
                    viewModel.Step = 1;
                    return this.View(viewModel);
                }

                Billing billing = null;
                var idSet = string.Format(
                    "CEREB.{1}{2}.{0}",
                    localNow.Year,
                    practice.AccountContract.BillingPeriodSize,
                    practice.AccountContract.BillingPeriodType);

                var invoiceStartUtc = PracticeController.ConvertToUtcDateTime(practice, selectedInvoiceInfo.Start);
                billing = db.Billings.SingleOrDefault(b => b.PracticeId == practice.Id
                    && b.MainAccountContractId == practice.ActiveAccountContractId
                    && b.ReferenceDate == invoiceStartUtc);

                if (billing == null)
                {
                    billing = new Billing
                       {
                           PracticeId = practice.Id,
                           AfterDueMonthlyTax = 1.00m, // 1%
                           AfterDueTax = 2.00m, // 2%
                           IssuanceDate = utcNow,
                           MainAmount = selectedInvoiceInfo.TotalAmount,
                           MainDiscount = selectedInvoiceInfo.TotalDiscount,
                           DueDate = PracticeController.ConvertToUtcDateTime(practice, selectedInvoiceInfo.DueDate),
                           IdentitySetName = idSet,
                           IdentitySetNumber = db.Billings.Count(b => b.PracticeId == practice.Id && b.IdentitySetName == idSet) + 1,
                           ReferenceDate = PracticeController.ConvertToUtcDateTime(practice, selectedInvoiceInfo.Start),
                           ReferenceDateEnd = PracticeController.ConvertToUtcDateTime(practice, selectedInvoiceInfo.End),
                           MainAccountContractId = practice.ActiveAccountContractId.Value,
                       };

                    db.Billings.AddObject(billing);
                }

                if (practice.AccountContract.BillingPaymentMethod == "PayPal Invoice")
                    this.ViewBag.IsPayPalInvoice = true;

                if (this.ModelState.IsValid)
                {
                    db.SaveChanges();

                    // adding PayPal invoice info
                    viewModel.PayPalInvoice = new GenerateInvoiceViewModel.PayPalInvoiceInfo
                        {
                            UserEmail = practice.Owner.Person.Email,
                            IssuanceDate = localNow.ToString("dd-MM-yyyy"),
                            Currency = "BRL - Reais",
                            Number = string.Format("{0}.{1}", billing.IdentitySetName, billing.IdentitySetNumber),
                            DuaDate = selectedInvoiceInfo.DueDate.ToString("dd-MM-yyyy"),
                            Terms = "Vencimento na data especificada",
                            Items = new List<GenerateInvoiceViewModel.PayPalInvoiceItem>(),
                        };

                    var strStartToEnd = selectedInvoiceInfo.End != null
                        ? string.Format(
                            "{0} até {1}",
                            selectedInvoiceInfo.Start.ToString("yyyy'-'MM'-'dd"),
                            selectedInvoiceInfo.End.Value.ToString("yyyy'-'MM'-'dd"))
                        : string.Format(
                            "{0}",
                            selectedInvoiceInfo.Start.ToString("yyyy'-'MM'-'dd"));

                    viewModel.PayPalInvoice.Items.Add(
                        new GenerateInvoiceViewModel.PayPalInvoiceItem
                            {
                                NameId = "Assinatura Cerebello",
                                Date = "",
                                Quantity = 1,
                                UnitPrice = selectedInvoiceInfo.TotalAmount.ToString("0.00", CultureInfo.InvariantCulture).Replace('.', ','),
                                Description = string.Format("Assinatura do plano profissional do Cerebello ({0})", strStartToEnd),
                            });

                    var periodType = practice.AccountContract.BillingPeriodType;
                    var periodSize = practice.AccountContract.BillingPeriodSize;
                    var discountReason =
                        periodType == "M" && periodSize == 1 ? "mensal" :
                        periodType == "M" && periodSize == 3 ? "trimestral" :
                        periodType == "M" && periodSize == 6 ? "semestral" :
                        periodType == "M" && periodSize == 12 || periodType == "Y" && periodSize == 1 ? "anual" :
                        "";

                    if (selectedInvoiceInfo.TotalDiscount > 0)
                    {
                        viewModel.PayPalInvoice.Items.Add(
                            new GenerateInvoiceViewModel.PayPalInvoiceItem
                                {
                                    NameId = "Desconto da Assinatura Cerebello",
                                    Date = "",
                                    Quantity = 1,
                                    UnitPrice = selectedInvoiceInfo.TotalDiscount.ToString("'-'0.00", CultureInfo.InvariantCulture).Replace('.', ','),
                                    Description = string.Format("Desconto na Assinatura (condições especiais para pagamento {0})", discountReason)
                                });
                    }

                    viewModel.Step = 2;
                    return this.View(viewModel);
                }
            }

            return this.View(viewModel);
        }
コード例 #5
0
        public ActionResult SetAccountPaymentInfo(ChangeContractViewModel viewModel)
        {
            var mainContract = dbPractice.AccountContract;

            string planId;
            Bus.ContractToPlan.TryGetValue(dbPractice.AccountContract.SYS_ContractType.UrlIdentifier, out planId);

            // because each plan has a different set of features,
            // this is going to be used by the view, to define the partial page that will be shown
            this.ViewBag.CurrentContractName = mainContract.SYS_ContractType.UrlIdentifier;

            if (!viewModel.AcceptedByUser)
            {
                this.ModelState.AddModelError(
                    () => viewModel.AcceptedByUser, "A caixa de checagem de aceitação do contrato precisa ser marcada para concluir o processo.");
            }

            if (mainContract.IsPartialBillingInfo)
            {
                if (planId == "ProfessionalPlan")
                {
                    // calculating values to see if the submited values are correct
                    var unitPrice = Bus.Pro.DOCTOR_PRICE;
                    Func<double, double, double> integ = (x, n) => Math.Pow(n, x) / Math.Log(n);
                    Func<double, double, double> integ0to = (x, n) => (integ(x, n) - integ(0, n));
                    Func<double, double> priceFactor = x => x * (1.0 - 0.1 * integ0to((x - 1) / 3.0, 0.75));
                    Func<double, double> price = (extraDoctors) => Math.Round(priceFactor(extraDoctors) * unitPrice * 100) / 100;

                    var dicValues = new Dictionary<string, decimal>(StringComparer.InvariantCultureIgnoreCase)
                        {
                            { "MONTH", Bus.Pro.PRICE_MONTH },
                            { "3-MONTHS", Bus.Pro.PRICE_QUARTER },
                            { "6-MONTHS", Bus.Pro.PRICE_SEMESTER },
                            { "12-MONTHS", Bus.Pro.PRICE_YEAR },
                        };

                    var dicDiscount = new Dictionary<string, decimal>(StringComparer.InvariantCultureIgnoreCase)
                        {
                            { "MONTH", 0 },
                            { "3-MONTHS", Bus.Pro. DISCOUNT_QUARTER },
                            { "6-MONTHS", Bus.Pro. DISCOUNT_SEMESTER },
                            { "12-MONTHS", Bus.Pro.DISCOUNT_YEAR },
                        };

                    var periodSizesDic = new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase)
                        {
                            { "MONTH", 1 },
                            { "3-MONTHS", 3 },
                            { "6-MONTHS", 6 },
                            { "12-MONTHS", 12 },
                        };

                    var dicount = 1m - dicDiscount[viewModel.PaymentModelName] / 100m;
                    var accountValue = dicValues[viewModel.PaymentModelName];
                    var doctorsValueWithoutDiscount = (decimal)Math.Round(price(viewModel.DoctorCount - 1))
                        * periodSizesDic[viewModel.PaymentModelName];

                    var finalValue = accountValue + doctorsValueWithoutDiscount * dicount;

                    var finalValueWithoutDiscount =
                        Bus.Pro.PRICE_MONTH * periodSizesDic[viewModel.PaymentModelName]
                        + doctorsValueWithoutDiscount;

                    // tolerance of R$ 0.10 in the final value... maybe the browser could not make the calculations correctly,
                    // but we must use that value, since it is the value that the user saw
                    if (Math.Abs(finalValue - viewModel.FinalValue) >= 0.10m)
                    {
                        this.ModelState.AddModelError(
                            () => viewModel.FinalValue,
                            "Seu browser apresentou um defeito no cálculo do valor final. Não foi possível processar sua requisição de upgrade.");
                    }

                    viewModel.ContractUrlId = planId;
                    viewModel.CurrentDoctorsCount = dbPractice.Users.Count(x => x.DoctorId != null);

                    if (this.ModelState.IsValid)
                    {
                        //// sending e-mail to [email protected]
                        //// to remember us to send the payment request
                        //var emailViewModel = new InternalUpgradeEmailViewModel(this.DbUser, viewModel);
                        //var toAddress = new MailAddress("*****@*****.**", this.DbUser.Person.FullName);
                        //var mailMessage = this.CreateEmailMessagePartial("InternalUpgradeEmail", toAddress, emailViewModel);
                        //this.SendEmailAsync(mailMessage).ContinueWith(t =>
                        //{
                        //    // observing exception so that it is not raised
                        //    var ex = t.Exception;

                        //    // todo: should do something when e-mail is not sent
                        //    // 1) use a schedule table to save a serialized e-mail, and then send it later
                        //    // 2) log a warning message somewhere stating that this e-mail was not sent
                        //    // send e-mail again is not an option, SendEmailAsync already tries a lot of times
                        //});

                        // changing the partial contract, to match the new billing settings
                        // Note: the contract will still be partial, and only when the user pays
                        //     the partial flag will be removed and the StartDate will be defined.
                        mainContract.CustomText = viewModel.WholeUserAgreement;
                        mainContract.DoctorsLimit = viewModel.DoctorCount;

                        mainContract.BillingAmount = finalValueWithoutDiscount;
                        mainContract.BillingDiscountAmount = finalValueWithoutDiscount - viewModel.FinalValue;
                        mainContract.BillingDueDay = viewModel.InvoceDueDayOfMonth;
                        mainContract.BillingPeriodCount = null;
                        mainContract.BillingPeriodSize = periodSizesDic[viewModel.PaymentModelName];
                        mainContract.BillingPeriodType = "M";
                        mainContract.BillingPaymentMethod = "PayPal Invoice";

                        this.db.SaveChanges();

                        // Creating the first billing
                        var utcNow = this.GetUtcNow();
                        var localNow = PracticeController.ConvertToLocalDateTime(dbPractice, utcNow);

                        Billing billing = null;
                        var idSet = string.Format(
                            "CEREB.{1}{2}.{0}",
                            localNow.Year,
                            mainContract.BillingPeriodSize,
                            mainContract.BillingPeriodType);

                        billing = db.Billings.SingleOrDefault(b => b.PracticeId == dbPractice.Id
                            && b.MainAccountContractId == dbPractice.ActiveAccountContractId
                            && b.ReferenceDate == null);

                        if (billing == null)
                        {
                            billing = new Billing
                            {
                                PracticeId = dbPractice.Id,
                                AfterDueMonthlyTax = 1.00m, // 1%
                                AfterDueTax = 2.00m, // 2%
                                IssuanceDate = utcNow,
                                MainAmount = (decimal)mainContract.BillingAmount,
                                MainDiscount = (decimal)mainContract.BillingDiscountAmount,
                                DueDate = PracticeController.ConvertToUtcDateTime(dbPractice, localNow.AddDays(10)),
                                IdentitySetName = idSet,
                                IdentitySetNumber = db.Billings.Count(b => b.PracticeId == dbPractice.Id && b.IdentitySetName == idSet) + 1,
                                ReferenceDate = PracticeController.ConvertToUtcDateTime(dbPractice, null),
                                ReferenceDateEnd = PracticeController.ConvertToUtcDateTime(dbPractice, null),
                                MainAccountContractId = dbPractice.ActiveAccountContractId.Value,
                            };

                            db.Billings.AddObject(billing);
                        }

                        this.db.SaveChanges();

                        // Using PayPal API to start an Express Checkout operation, and then redirecting user to PayPal.
                        var operation = new PayPalSetExpressCheckoutOperation();
                        ConfigAccountController.FillOperationDetails(operation, dbPractice, mainContract, billing);
                        var practice = this.dbPractice.UrlIdentifier;
                        operation.PaymentRequests[0].NotifyUrl = UseExternalIpIfDebug(this.Url.ActionAbsolute("PayPalNotification", new { practice }));
                        var opResult = this.SetExpressCheckout(operation, "PayPalConfirm", "PayPalCancel", new { practice });

                        if (opResult.Errors != null && opResult.Errors.Any())
                            return new StatusCodeResult(HttpStatusCode.InternalServerError, opResult.Errors[0].LongMessage);

                        return this.RedirectToCheckout(opResult);
                    }

                    return this.View(viewModel);
                }
            }

            return this.HttpNotFound();
        }