Example #1
0
        private List <AccountantMonthlyReceipt> FindReceipt(int year, int month)
        {
            var begin = new DateTime(year, month, 1, 0, 0, 0, DateTimeKind.Utc); // first second of last month

            // the first month we use new receipt identifier format is 2019/11
            if (begin >= new DateTime(2019, 11, 1, 0, 0, 0, DateTimeKind.Utc))
            {
                // set receipt identifier
                CommerceModule.SetReceiptIdentifier(this.SiteDatabase, begin);
            }

            var end = begin.AddMonths(1);

            end = end.AddMilliseconds(-1); // one second before start of this month

            var thaiTimeZone        = TimeZoneInfo.FindSystemTimeZoneById("SE Asia Standard Time");
            var negativeTicksOffset = thaiTimeZone.BaseUtcOffset.Ticks * -1;

            begin = begin.AddTicks(negativeTicksOffset);
            end   = end.AddTicks(negativeTicksOffset);

            var paymentsThisMonth = this.SiteDatabase.Query <PaymentLog>()
                                    .Where(l => l.__createdAt >= begin && l.__createdAt <= end)
                                    .OrderBy(l => l.__createdAt)
                                    .ThenBy(l => l.Id).ToList();

            List <Receipt> receipts = new List <Receipt>();

            foreach (var l in paymentsThisMonth)
            {
                var receipt = this.SiteDatabase.Query <Receipt>().Where(r => r.PaymentLogId == l.Id).FirstOrDefault();
                if (receipt == null)
                {
                    continue;
                }
                receipts.Add(receipt);
            }

            var result = this.GetAccountantMonthlyReceipt(receipts, paymentsThisMonth);

            return(result);
        }
Example #2
0
        public static void HandlePayment(NancyBlackDatabase db, PaymentLog log, DateTime paidWhen)
        {
            // ensure only one thread is processing this so
            lock (BaseModule.GetLockObject(log.SaleOrderIdentifier))
            {
                db.Transaction(() =>
                {
                    paidWhen = DateTime.SpecifyKind(paidWhen, DateTimeKind.Utc);

                    // find the sale order
                    var so = db.Query <SaleOrder>()
                             .Where(row => row.SaleOrderIdentifier == log.SaleOrderIdentifier)
                             .FirstOrDefault();


                    bool isPaymentReceived = false;

                    JArray exceptions = new JArray();

                    if (so == null)
                    {
                        exceptions.Add(JObject.FromObject(new
                        {
                            type        = "Wrong SO Number",
                            description = "Wrong SO Number"
                        }));

                        goto EndPayment;
                    }

                    log.SaleOrderId = so.Id;
                    log.PaymentDate = paidWhen;

                    // Wrong Payment Status
                    if (so.PaymentStatus == PaymentStatus.PaymentReceived)
                    {
                        so.IsDuplicatePayment = true;
                        exceptions.Add(JObject.FromObject(new
                        {
                            type        = "Wrong Status",
                            description = string.Format(
                                "Current paymentlog status of SO is: {0}", PaymentStatus.DuplicatePayment)
                        }));
                    }

                    // Error code received
                    if (log.IsErrorCode)
                    {
                        so.PaymentStatus = PaymentStatus.WaitingForPayment;
                        exceptions.Add(JObject.FromObject(new
                        {
                            type        = "Error Code",
                            description = "Error Code Received from Payment Processor: " + log.ResponseCode
                        }));

                        goto EndPayment;
                    }


                    var saleOrderPaymentLogs = db.Query <PaymentLog>()
                                               .Where(p => p.SaleOrderIdentifier == so.SaleOrderIdentifier);

                    var totalSuccessful        = saleOrderPaymentLogs.Where(l => l.IsPaymentSuccess).Count();
                    log.SuccessfulPaymentIndex = (totalSuccessful + 1) - 1;

                    // after this line will never be run until EndPayment when IsErrorCode == true
                    if (so.PaymentStatus != PaymentStatus.PaymentReceived && log.Amount != so.TotalAmount)
                    {
                        log.IsPaymentSuccess   = true;
                        so.PaymentStatus       = PaymentStatus.Deposit;
                        so.PaymentReceivedDate = DateTime.Now; // Need to use this to manage queue

                        exceptions.Add(JObject.FromObject(new
                        {
                            type        = "Split Payment",
                            description = string.Format(
                                "Expects: {0} amount from SO, payment is {1}", so.TotalAmount, log.Amount)
                        }));


                        var splitPaymentLogs = (from sPLog in saleOrderPaymentLogs
                                                where sPLog.IsErrorCode == false
                                                select sPLog).ToList();

                        isPaymentReceived = so.TotalAmount <= splitPaymentLogs.Sum(splog => splog.Amount) + log.Amount;
                    }

                    if (exceptions.Count == 0 || isPaymentReceived)
                    {
                        log.IsPaymentSuccess = true;

                        so.PaymentStatus       = PaymentStatus.PaymentReceived;
                        so.PaymentReceivedDate = DateTime.Now;
                    }

                    EndPayment:

                    log.Exception = exceptions;
                    db.UpsertRecord <PaymentLog>(log);

                    CommerceModule.PaymentOccured(so, db);

                    if (log.IsPaymentSuccess)
                    {
                        // Set Receipt number
                        var rc = db.UpsertRecord <Receipt>(new Receipt()
                        {
                            SaleOrderId = so.Id, PaymentLogId = log.Id
                        });
                        db.UpsertRecord(rc);

                        CommerceModule.PaymentSuccess(so, db);
                    }

                    db.UpsertRecord <SaleOrder>(so);

                    // reset the one time code used
                    foreach (var item in so.ItemsDetail)
                    {
                        if (item.Url.StartsWith("/promotions/code/archive-onetime"))
                        {
                            // do nothing
                        }
                        else if (item.Url.StartsWith("/promotions/code"))
                        {
                            if (item.Attributes.onetime != null)
                            {
                                var product = db.GetById <Product>(item.Id);
                                if (product != null)
                                {
                                    product.Url = product.Url.Replace("/promotions/code", "/promotions/code/archive-onetime");
                                    db.UpsertRecord(product);
                                }
                            }
                        }
                    }

                    // Automate change status to WaitingForOrder for add item to PO
                    if (exceptions.Count == 0 || isPaymentReceived)
                    {
                        if (so.Status == SaleOrderStatus.Confirmed)
                        {
                            so.Status = SaleOrderStatus.WaitingForOrder;
                            db.UpsertRecord <SaleOrder>(so);
                        }
                    }
                });


                CommerceModule.SetReceiptIdentifier(db, paidWhen);
            }
        }