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