Esempio n. 1
0
        private List <ShipmentAction> BuildShipmentInvoiceActions(ShopifyOrder orderRecord)
        {
            var output = new List <ShipmentAction>();

            foreach (var soShipment in orderRecord.SoShipments())
            {
                var action = new ShipmentAction();
                action.ShipmentNbr = soShipment.AcumaticaShipmentNbr;
                action.ShipmentHref
                    = _acumaticaUrlService.AcumaticaShipmentUrl(soShipment.AcumaticaShipmentNbr);

                action.InvoiceNbr    = soShipment.AcumaticaInvoiceNbr;
                action.InvoiceAmount = soShipment.AcumaticaInvoiceAmount.Value;
                action.InvoiceTax    = soShipment.AcumaticaInvoiceTax.Value;

                if (soShipment.ShopifyFulfillment == null)
                {
                    action.ActionCode = ActionCode.CreateInShopify;
                }
                else
                {
                    action.ActionCode           = ActionCode.None;
                    action.ShopifyFulfillmentId = soShipment.ShopifyFulfillment.ShopifyFulfillmentId;
                }

                output.Add(action);
            }

            return(output);
        }
        public void ValidatePayment(ShopifyOrder order, PaymentAction action)
        {
            action.Validation = new ValidationResult();

            var transaction = order
                              .ShopifyTransactions.FirstOrDefault(x => x.ShopifyTransactionId == action.ShopifyTransactionId);

            //if (transaction == null)
            //{
            //    return;
            //}

            if (action.ActionCode == ActionCode.CreateInAcumatica)
            {
                action.Validation = ReadyToCreatePayment(transaction);
                return;
            }

            if (action.ActionCode == ActionCode.UpdateInAcumatica)
            {
                action.Validation = ReadyToUpdatePayment(transaction);
                return;
            }

            if (action.ActionCode == ActionCode.ReleaseInAcumatica)
            {
                action.Validation = ReadyToRelease(transaction);
                return;
            }
        }
Esempio n. 3
0
        private OrderAction BuildOrderPendingAction(ShopifyOrder record)
        {
            var output = new OrderAction();
            var order  = _shopifyJsonService.RetrieveOrder(record.ShopifyOrderId);

            output.ShopifyOrderId   = record.ShopifyOrderId;
            output.ShopifyOrderHref = _shopifyUrlService.ShopifyOrderUrl(record.ShopifyOrderId);
            output.ShopifyOrderName = order.name;

            output.Validation = new ValidationResult();
            output.ActionCode = ActionCode.None;

            if (!record.ExistsInAcumatica())
            {
                output.ActionCode =
                    order.IsCancelled || order.AreAllLineItemsRefunded
                        ? ActionCode.CreateBlankSyncRecord
                        : ActionCode.CreateInAcumatica;
            }
            else // Exists in Acumatica
            {
                output.AcumaticaSalesOrderNbr = record.AcumaticaSalesOrder.AcumaticaOrderNbr;
                output.AcumaticaSalesOrderHref
                    = _acumaticaUrlService.AcumaticaSalesOrderUrl(
                          SalesOrderType.SO, record.AcumaticaSalesOrder.AcumaticaOrderNbr);

                if (record.NeedsOrderPut ||
                    record.ShopifyTotalQuantity != record.SyncedSalesOrder().AcumaticaQtyTotal)
                {
                    output.ActionCode = ActionCode.UpdateInAcumatica;
                }
            }

            return(output);
        }
 public static bool IsPaid(this ShopifyOrder order)
 {
     return
         (order.ShopifyFinancialStatus == FinancialStatus.Paid ||
          order.ShopifyFinancialStatus == FinancialStatus.PartiallyRefunded ||
          order.ShopifyFinancialStatus == FinancialStatus.Refunded);
 }
Esempio n. 5
0
        private void PullTransactionsFromShopify(ShopifyOrder orderRecord)
        {
            var transactionsJson = _orderApi.RetrieveTransactions(orderRecord.ShopifyOrderId);
            var transactions     = transactionsJson.DeserializeFromJson <TransactionList>();
            var order            = _shopifyJsonService.RetrieveOrder(orderRecord.ShopifyOrderId);

            foreach (var transaction in transactions.transactions)
            {
                var transactionRecord = _orderRepository.RetrieveTransaction(transaction.id);
                if (transactionRecord != null)
                {
                    transactionRecord.LastUpdated = DateTime.UtcNow;
                    _orderRepository.SaveChanges();
                    continue;
                }

                using (var dbTransaction = _orderRepository.BeginTransaction())
                {
                    var record = new ShopifyTransaction();

                    if (transaction.kind == TransactionKind.Refund)
                    {
                        record.IsSyncableToPayment = true;

                        var refund = order.RefundByTransaction(transaction.id);
                        if (refund != null)
                        {
                            record.ShopifyRefundId = refund.id;
                            record.IsPureCancel    = refund.IsPureCancel;
                        }
                    }

                    if (transaction.kind == TransactionKind.Capture || transaction.kind == TransactionKind.Sale)
                    {
                        record.IsSyncableToPayment = true;
                    }

                    record.ShopifyOrderId        = transaction.order_id;
                    record.ShopifyTransactionId  = transaction.id;
                    record.ShopifyStatus         = transaction.status;
                    record.ShopifyKind           = transaction.kind;
                    record.ShopifyGateway        = transaction.gateway;
                    record.ShopifyAmount         = transaction.amount;
                    record.ShopifyOrderMonsterId = orderRecord.MonsterId;
                    record.DateCreated           = DateTime.UtcNow;
                    record.LastUpdated           = DateTime.UtcNow;

                    _logService.Log(LogBuilder.DetectedNewShopifyTransaction(record));
                    _orderRepository.InsertTransaction(record);

                    _shopifyJsonService.Upsert(
                        ShopifyJsonType.Transaction, transaction.id, transaction.SerializeToJson());
                    dbTransaction.Commit();
                }
            }

            orderRecord.NeedsTransactionGet = false;
            _orderRepository.SaveChanges();
        }
Esempio n. 6
0
        public void Validate(ShopifyOrder orderRecord, ShipmentAction action)
        {
            var soShipment = orderRecord.SoShipments()
                             .First(x => x.AcumaticaShipmentNbr == action.ShipmentNbr &&
                                    x.AcumaticaInvoiceNbr == action.InvoiceNbr);

            action.Validation = Validate(soShipment);
        }
Esempio n. 7
0
        private List <AdjustmentAction> BuildRefundAdjustmentActions(ShopifyOrder orderRecord)
        {
            var output = new List <AdjustmentAction>();

            foreach (var creditAdj in orderRecord.CreditAdustmentRefunds())
            {
                var action = new AdjustmentAction();
                action.ActionCode      = ActionCode.None;
                action.ShopifyOrderId  = orderRecord.ShopifyOrderId;
                action.ShopifyRefundId = creditAdj.ShopifyRefundId;

                action.MemoType   = AdjustmentMemoType.CreditMemo;
                action.MemoAmount = creditAdj.CreditAdjustment;


                if (creditAdj.AcumaticaMemo == null)
                {
                    action.ActionCode = ActionCode.CreateInAcumatica;
                }

                if (creditAdj.AcumaticaMemo != null)
                {
                    action.AcumaticaRefNbr  = creditAdj.AcumaticaMemo.AcumaticaRefNbr;
                    action.AcumaticaDocType = creditAdj.AcumaticaMemo.AcumaticaDocType;
                    action.AcumaticaHref
                        = _acumaticaUrlService.AcumaticaInvoiceUrl(
                              SalesInvoiceType.Credit_Memo, creditAdj.AcumaticaMemo.AcumaticaRefNbr);
                }

                if (creditAdj.AcumaticaMemo != null &&
                    !creditAdj.AcumaticaMemo.NeedManualApply &&
                    creditAdj.AcumaticaMemo.NeedRelease)
                {
                    action.ActionCode = ActionCode.ReleaseInAcumatica;
                }

                if (creditAdj.AcumaticaMemo != null &&
                    creditAdj.AcumaticaMemo.NeedManualApply)
                {
                    action.ActionCode = ActionCode.NeedManualApply;
                }

                output.Add(action);
            }

            foreach (var debitAdj in orderRecord.DebitAdustmentRefunds())
            {
                var action = new AdjustmentAction();
                action.ActionCode = ActionCode.CreateInAcumatica;
                action.MemoType   = AdjustmentMemoType.DebitMemo;
                action.MemoAmount = debitAdj.DebitAdjustment;

                output.Add(action);
            }

            return(output);
        }
Esempio n. 8
0
        private void UpsertOrderAndCustomer(Order order)
        {
            var monsterCustomerRecord = _shopifyCustomerPull.UpsertCustomer(order.customer);

            using (var transaction = _orderRepository.BeginTransaction())
            {
                var existingOrder = _orderRepository.RetrieveOrder(order.id);
                if (existingOrder == null)
                {
                    var newOrder = new ShopifyOrder();

                    newOrder.ShopifyOrderId             = order.id;
                    newOrder.ShopifyOrderNumber         = order.name;
                    newOrder.ShopifyTotalPrice          = order.total_price;
                    newOrder.ShopifyFinancialStatus     = order.financial_status;
                    newOrder.ShopifyFulfillmentStatus   = order.fulfillment_status;
                    newOrder.ShopifyIsCancelled         = order.IsCancelled;
                    newOrder.ShopifyAreAllItemsRefunded = order.AreAllLineItemsRefunded;
                    newOrder.ShopifyTotalQuantity       = order.NetOrderedQuantity;

                    newOrder.NeedsOrderPut       = false;
                    newOrder.NeedsTransactionGet = true;
                    newOrder.ErrorCount          = 0;
                    newOrder.Ignore = false;

                    newOrder.CustomerMonsterId = monsterCustomerRecord.MonsterId;
                    newOrder.DateCreated       = DateTime.UtcNow;
                    newOrder.LastUpdated       = DateTime.UtcNow;

                    _executionLogService.Log(LogBuilder.DetectedNewShopifyOrder(newOrder));
                    _orderRepository.InsertOrder(newOrder);
                }
                else
                {
                    existingOrder.ShopifyTotalPrice          = order.total_price;
                    existingOrder.ShopifyFinancialStatus     = order.financial_status;
                    existingOrder.ShopifyFulfillmentStatus   = order.fulfillment_status;
                    existingOrder.ShopifyIsCancelled         = order.IsCancelled;
                    existingOrder.ShopifyAreAllItemsRefunded = order.AreAllLineItemsRefunded;
                    existingOrder.ShopifyTotalQuantity       = order.NetOrderedQuantity;

                    if (existingOrder.StatusChangeDetected(order))
                    {
                        existingOrder.NeedsOrderPut = true;
                    }

                    existingOrder.NeedsTransactionGet = true;
                    existingOrder.LastUpdated         = DateTime.UtcNow;

                    _executionLogService.Log(LogBuilder.DetectedUpdateShopifyOrder(existingOrder));
                    _orderRepository.SaveChanges();
                }

                _shopifyJsonService.Upsert(ShopifyJsonType.Order, order.id, order.SerializeToJson());
                transaction.Commit();
            }
        }
Esempio n. 9
0
        public void ParseShopifyEmail()
        {
            var sut = new ShopifyOrder(shopifyEmail);

            Assert.Equal("1130", sut.OrderID);
            Assert.Equal(114.05, sut.OrderTotal);
            Assert.Equal("https://liftergifts.myshopify.com/admin/orders/1853957537907", sut.OrderUrl);
            Assert.Equal(2.04, sut.ShippingCharge);
            Assert.Equal(3, sut.Transactions.Count);
        }
Esempio n. 10
0
        // *** IMPORTANT => Shopify is the single source of truth (SSoT) for Payment Transactions
        //  ... whereas Acumatica is the SSoT for goods issued to Customer via Shipments
        //
        public static decimal TheoreticalPaymentRemaining(this ShopifyOrder order)
        {
            // UPDATE => We'll play conservatively for system stability and clarity.
            //  ... This is computed figure is inclusive of Cancels, Returns and InStock
            //  ... aka indeterminate. If a Return is received before the Order is Complete,
            //  ... the user will bear the responsibility of manually applying Payments and Refunds.
            //
            var output = order.ShopifyNetPayment() - order.AcumaticaInvoiceTotal();

            return(output <= 0.00m ? 0.00m : output);
        }
Esempio n. 11
0
        private List <PaymentAction> BuildRefundPaymentActions(ShopifyOrder orderRecord)
        {
            var output = new List <PaymentAction>();

            foreach (var refundTrans in orderRecord.RefundTransactions())
            {
                var refundAction = new PaymentAction();

                refundAction.ShopifyTransactionId = refundTrans.ShopifyTransactionId;
                refundAction.TransDesc            = $"Shopify Refund ({refundTrans.ShopifyTransactionId})";
                refundAction.PaymentGateway       = refundTrans.ShopifyGateway;
                refundAction.Amount = refundTrans.ShopifyAmount;

                var refund = orderRecord.Refund(refundTrans.ShopifyRefundId.Value);

                refundAction.HasShipping = refund.HasShipping();
                refundAction.Shipping    = refund.Shipping;
                refundAction.ShippingTax = refund.ShippingTax;

                refundAction.ActionCode = ActionCode.None;

                if (!refundTrans.ExistsInAcumatica())
                {
                    refundAction.ActionCode = ActionCode.CreateInAcumatica;
                }

                if (refundTrans.ExistsInAcumatica())
                {
                    refundAction.AcumaticaPaymentRef = refundTrans.AcumaticaPayment.AcumaticaRefNbr;
                    refundAction.AcumaticaHref
                        = _acumaticaUrlService.AcumaticaPaymentUrl(
                              PaymentType.CustomerRefund, refundTrans.AcumaticaPayment.AcumaticaRefNbr);
                }

                if (refundTrans.ExistsInAcumatica() &&
                    !refundTrans.AcumaticaPayment.NeedManualApply &&
                    !refundTrans.IsReleased())
                {
                    refundAction.ActionCode = ActionCode.ReleaseInAcumatica;
                }

                if (refundTrans.ExistsInAcumatica() &&
                    refundTrans.AcumaticaPayment.NeedManualApply)
                {
                    refundAction.ActionCode = ActionCode.NeedManualApply;
                }

                output.Add(refundAction);
            }

            return(output);
        }
Esempio n. 12
0
        private OrderAnalyzerResultsRow MakeOrderAnalyzerResults(ShopifyOrder order)
        {
            var output = new OrderAnalyzerResultsRow();

            output.ShopifyOrderId   = order.ShopifyOrderId;
            output.ShopifyOrderNbr  = order.ShopifyOrderNumber.ToString();
            output.ShopifyOrderHref = _shopifyUrlService.ShopifyOrderUrl(order.ShopifyOrderId);

            // TODO - need to add a flag that indicates this Order has been archived
            //
            var shopifyOrder = _shopifyJsonService.RetrieveOrder(order.ShopifyOrderId);

            output.ShopifyOrderTotal = shopifyOrder.NetOrderTotal;
            output.ShopifyNetPayment = order.ShopifyNetPayment();

            output.ShopifyFinancialStatus     = order.ShopifyFinancialStatus;
            output.ShopifyFulfillmentStatus   = order.ShopifyFulfillmentStatus;
            output.ShopifyIsCancelled         = order.ShopifyIsCancelled;
            output.ShopifyAreAllItemsRefunded = order.ShopifyAreAllItemsRefunded;

            var acumaticaSalesOrder = order.AcumaticaSalesOrder;

            if (acumaticaSalesOrder != null && acumaticaSalesOrder.AcumaticaOrderNbr != AcumaticaSyncConstants.BlankRefNbr)
            {
                output.AcumaticaSalesOrderNbr  = acumaticaSalesOrder.AcumaticaOrderNbr;
                output.AcumaticaSalesOrderHref =
                    _acumaticaUrlService
                    .AcumaticaSalesOrderUrl(SalesOrderType.SO, acumaticaSalesOrder.AcumaticaOrderNbr);
                output.AcumaticaStatus     = acumaticaSalesOrder.AcumaticaStatus;
                output.AcumaticaOrderTotal = acumaticaSalesOrder.AcumaticaOrderTotal;
            }

            if (order.IsPaymentSynced())
            {
                output.AcumaticaOrderPayment = order.AcumaticaPaymentAmount();
                output.AcumaticaNetPayment   = order.AcumaticaNetPaymentAmount();
            }
            else
            {
                output.AcumaticaOrderPayment = 0.00m;
                output.AcumaticaNetPayment   = 0.00m;
            }

            output.AcumaticaInvoiceTotal = order.AcumaticaInvoiceTotal();

            output.Ignore            = order.Ignore;
            output.HasError          = order.ExceedsErrorLimit();
            output.HasPendingActions = _pendingActionService.Create(order, false).HasPendingActions;

            return(output);
        }
Esempio n. 13
0
        // Invoke the Acumatica Customer Sync
        //
        public AcumaticaCustomer PushNonExistentCustomer(ShopifyOrder shopifyOrder)
        {
            var customer = _syncOrderRepository
                           .RetrieveCustomer(shopifyOrder.ShopifyCustomer.ShopifyCustomerId);

            if (customer.HasMatch())
            {
                return(customer.Match());
            }
            else
            {
                return(_acumaticaCustomerSync.PushCustomer(customer));
            }
        }
Esempio n. 14
0
        private PaymentAction BuildPaymentActions(ShopifyOrder orderRecord)
        {
            var paymentAction = new PaymentAction();

            paymentAction.ActionCode = ActionCode.None;
            paymentAction.Validation = new ValidationResult();

            if (orderRecord.HasPayment())
            {
                var payment = orderRecord.PaymentTransaction();
                paymentAction.ShopifyTransactionId = payment.ShopifyTransactionId;
                paymentAction.TransDesc            = $"Shopify Payment ({payment.ShopifyTransactionId})";
                paymentAction.PaymentGateway       = payment.ShopifyGateway;
                paymentAction.Amount = payment.ShopifyAmount;

                paymentAction.ActionCode = ActionCode.None;

                if (!payment.ExistsInAcumatica())
                {
                    paymentAction.ActionCode = ActionCode.CreateInAcumatica;
                }

                if (payment.ExistsInAcumatica())
                {
                    paymentAction.AcumaticaPaymentRef = payment.AcumaticaPayment.AcumaticaRefNbr;
                    paymentAction.AcumaticaHref
                        = _acumaticaUrlService.AcumaticaPaymentUrl(
                              PaymentType.Payment, payment.AcumaticaPayment.AcumaticaRefNbr);

                    if (orderRecord.OriginalPaymentNeedsUpdateForRefund())
                    {
                        paymentAction.ActionCode = ActionCode.UpdateInAcumatica;
                    }
                    else if (payment.ExistsInAcumatica() && payment.AcumaticaPayment.NeedRelease)
                    {
                        paymentAction.ActionCode = ActionCode.ReleaseInAcumatica;
                    }
                }
            }
            else
            {
                paymentAction.ShopifyTransactionId = -1;
                paymentAction.TransDesc            = $"Shopify Payment not found yet";
                paymentAction.PaymentGateway       = "No Gateway";
                paymentAction.Amount     = 0.00m;
                paymentAction.ActionCode = ActionCode.None;
            }

            return(paymentAction);
        }
Esempio n. 15
0
        private void UpsertOrderFulfillment(ShopifyOrder orderRecord, Fulfillment fulfillment)
        {
            var fulfillmentRecord
                = orderRecord
                  .ShopifyFulfillments
                  .FirstOrDefault(x => x.ShopifyFulfillmentId == fulfillment.id);

            if (fulfillmentRecord != null)
            {
                // Existing Fulfillment Record
                //
                fulfillmentRecord.ShopifyStatus = fulfillment.status;
                fulfillmentRecord.LastUpdated   = DateTime.UtcNow;

                _orderRepository.SaveChanges();
                return;
            }

            var matchedRecord
                = orderRecord
                  .ShopifyFulfillments
                  .FirstOrDefault(x => x.ShopifyTrackingNumber == fulfillment.tracking_number);

            if (matchedRecord != null)
            {
                // Matched via Tracking Number in Shopify
                //
                _executionLogService.Log(
                    LogBuilder.FillingUnknownShopifyFulfillmentRefByTracking(matchedRecord));

                matchedRecord.ShopifyFulfillmentId = fulfillment.id;
                matchedRecord.LastUpdated          = DateTime.UtcNow;
                _orderRepository.SaveChanges();
            }
            else
            {
                // Creating new Fulfillment Record
                //
                var newRecord = new ShopifyFulfillment();
                newRecord.ShopifyOrderMonsterId = orderRecord.MonsterId;
                newRecord.ShopifyFulfillmentId  = fulfillment.id;
                newRecord.ShopifyOrderId        = orderRecord.ShopifyOrderId;
                newRecord.ShopifyStatus         = fulfillment.status;
                newRecord.DateCreated           = DateTime.UtcNow;
                newRecord.LastUpdated           = DateTime.UtcNow;

                _orderRepository.InsertFulfillment(newRecord);
            }
        }
Esempio n. 16
0
        // Create new Sales Order
        //
        private SalesOrder BuildNewSalesOrder(ShopifyOrder shopifyOrderRecord, AcumaticaCustomer customer)
        {
            // Get the Shopify Order
            //
            var shopifyOrder = _shopifyJsonService.RetrieveOrder(shopifyOrderRecord.ShopifyOrderId);

            // Header
            //
            var salesOrder = BuildNewSalesOrderHeader(shopifyOrderRecord, shopifyOrder, customer);

            // Detail
            //
            salesOrder.Details = BuildSalesOrderDetail(shopifyOrder);

            // Billing Address & Contact
            //
            salesOrder.BillToContactOverride = true.ToValue();
            salesOrder.BillToContact         = BuildContact(shopifyOrder, shopifyOrder.billing_address);
            salesOrder.BillToAddressOverride = true.ToValue();
            salesOrder.BillToAddress         = BuildAddress(shopifyOrder.billing_address);

            // Shipping Address & Contact
            //
            salesOrder.ShipToContactOverride = true.ToValue();
            salesOrder.ShipToContact         = BuildContact(shopifyOrder, shopifyOrder.shipping_address);
            salesOrder.ShipToAddressOverride = true.ToValue();
            salesOrder.ShipToAddress         = BuildAddress(shopifyOrder.shipping_address);

            if (!shopifyOrder.MaybeShippingRateTitle.IsNullOrEmpty())
            {
                var carrierToShipVia
                    = _settingsRepository.RetrieveRateToShipVia(shopifyOrder.MaybeShippingRateTitle);

                if (carrierToShipVia != null)
                {
                    salesOrder.ShipVia = carrierToShipVia.AcumaticaShipViaId.ToValue();
                }
            }

            // Payment optimization *** FAIL - PENDING ACUMATICA SUPPORT ***
            //
            //var payment = _acumaticaOrderPaymentPut.BuildPaymentForCreate(shopifyOrderRecord.PaymentTransaction());
            //salesOrder.Payments = new List<object> { payment };

            salesOrder.PaymentRef = shopifyOrderRecord.PaymentTransaction().ShopifyTransactionId.ToString().ToValue();

            return(salesOrder);
        }
Esempio n. 17
0
        private void InjectTotalsFromAcumatica(ShopifyOrder shopifyOrderRecord, OrderAnalysisTotals output)
        {
            SalesOrder acumaticaOrder    = null;
            var        acumaticaOrderNbr = shopifyOrderRecord.AcumaticaSalesOrder.AcumaticaOrderNbr;

            _acumaticaHttpContext.SessionRun(() =>
            {
                var json = _salesOrderClient
                           .RetrieveSalesOrder(acumaticaOrderNbr, SalesOrderType.SO, Expand.Totals);
                acumaticaOrder = json.ToSalesOrderObj();
            });

            output.AcumaticaOrderLineTotal = (decimal)acumaticaOrder.Totals.LineTotalAmount.value;
            output.AcumaticaOrderFreight   = (decimal)acumaticaOrder.Totals.Freight.value;
            output.AcumaticaTaxTotal       = (decimal)acumaticaOrder.Totals.TaxTotal.value;
            output.AcumaticaOrderTotal     = (decimal)acumaticaOrder.OrderTotal.value;
        }
        public static FinAnalyzer ToFinAnalyzer(this ShopifyOrder orderRecord, Order shopifyOrder)
        {
            var FinAnalyzer = new FinAnalyzer();

            FinAnalyzer.ExternalRefNbr = shopifyOrder.id.ToString();

            FinAnalyzer.Freight.Price         = shopifyOrder.ShippingTotal;
            FinAnalyzer.Freight.TaxableAmount = shopifyOrder.IsShippingTaxable ? shopifyOrder.ShippingTotal : 0m;
            FinAnalyzer.Freight.TaxLines      = shopifyOrder.shipping_lines.ToFinAnalyzerTaxLines();
            FinAnalyzer.Freight.TaxAmount     = shopifyOrder.ShippingTax;

            foreach (var line_item in shopifyOrder.line_items)
            {
                var xferLineItem = new FinAnalyzerLineItem();
                xferLineItem.ExternalRefNbr = line_item.id.ToString();
                xferLineItem.InventoryID    = line_item.sku;
                xferLineItem.Quantity       = line_item.quantity;
                xferLineItem.UnitPrice      = line_item.UnitPriceAfterDiscount;
                xferLineItem.TaxableAmount  = line_item.TaxableAmount;
                xferLineItem.TaxAmount      = line_item.Tax;
                xferLineItem.TaxLines       = line_item.tax_lines.ToFinAnalyzerTaxLines();
                FinAnalyzer.LineItems.Add(xferLineItem);
            }

            foreach (var refund in shopifyOrder.refunds)
            {
                var xferRefund = new FinAnalyzerRefund();
                if (refund.transactions.Any())
                {
                    xferRefund.ExternalRefNbr = refund.transactions.First().id.ToString();
                }

                xferRefund.TaxableAmount = refund.TotalTaxableLineAndShippingAmount;
                xferRefund.LineItemTotal = refund.LineItemTotal;
                xferRefund.LineItemsTax  = refund.TotalLineItemTax;
                xferRefund.Freight       = refund.TotalShippingAdjustment;
                xferRefund.FreightTax    = refund.TotalShippingAdjustmentTax;
                xferRefund.Credit        = refund.CreditMemoTotal;
                xferRefund.Debit         = refund.DebitMemoTotal;
                xferRefund.RefundAmount  = refund.PaymentTotal;
                FinAnalyzer.Refunds.Add(xferRefund);
            }

            FinAnalyzer.Payment = orderRecord.ShopifyPaymentAmount();
            return(FinAnalyzer);
        }
        public void ValidateRefundPayment(ShopifyOrder order, PaymentAction action)
        {
            var transaction = order
                              .ShopifyTransactions
                              .First(x => x.ShopifyTransactionId == action.ShopifyTransactionId);

            action.Validation = new ValidationResult();

            if (action.ActionCode == ActionCode.CreateInAcumatica)
            {
                action.Validation = ReadyToCreateRefundPayment(transaction);
            }

            if (action.ActionCode == ActionCode.ReleaseInAcumatica)
            {
                action.Validation = ReadyToReleaseRefundPayment(transaction);
            }
        }
Esempio n. 20
0
        // Update existing Sales Order
        //
        public SalesOrderUpdate BuildSalesOrderUpdate(ShopifyOrder shopifyOrderRecord)
        {
            var shopifyOrder     = _shopifyJsonService.RetrieveOrder(shopifyOrderRecord.ShopifyOrderId);
            var salesOrderRecord = shopifyOrderRecord.SyncedSalesOrder();

            var existingSalesOrder
                = _salesOrderClient
                  .RetrieveSalesOrder(
                      salesOrderRecord.AcumaticaOrderNbr, SalesOrderType.SO, SalesOrderExpand.Details)
                  .ToSalesOrderObj();

            var salesOrderUpdate = new SalesOrderUpdate();

            salesOrderUpdate.OrderType = existingSalesOrder.OrderType.Copy();
            salesOrderUpdate.OrderNbr  = existingSalesOrder.OrderNbr.Copy();
            salesOrderUpdate.Hold      = false.ToValue();

            // Update the Shipping Cost
            //
            salesOrderUpdate.FreightPrice         = ((double)shopifyOrder.NetShippingPrice).ToValue();
            salesOrderUpdate.OverrideFreightPrice = true.ToValue();

            foreach (var line_item in shopifyOrder.line_items)
            {
                var variant =
                    _syncInventoryRepository.RetrieveVariant(line_item.variant_id.Value, line_item.sku);

                var stockItemId      = variant.MatchedStockItem().ItemId;
                var salesOrderDetail = existingSalesOrder.DetailByInventoryId(stockItemId);

                var detail = new SalesOrderUpdateDetail();
                detail.id          = salesOrderDetail.id;
                detail.OrderQty    = ((double)line_item.NetOrderedQuantity).ToValue();
                detail.InventoryID = variant.MatchedStockItem().ItemId.ToValue();

                salesOrderUpdate.Details.Add(detail);
            }

            var taxTransfer = shopifyOrder.ToSerializedAndZippedTaxTransfer();

            salesOrderUpdate.custom = new SalesOrderUsrTaxSnapshot(taxTransfer);
            return(salesOrderUpdate);
        }
        /// <summary>
        /// A method that will throw an exception which looks like { errors: { "order" : [ "some error message" ] } }
        /// </summary>
        /// <returns></returns>
        public async Task ThrowArrayException()
        {
            var request = RequestEngine.CreateRequest("orders.json", Method.POST);

            //Creating an order with tax lines on both line items and the order will return an error
            var order = new ShopifyOrder()
            {
                CreatedAt = DateTime.UtcNow,
                LineItems = new List <ShopifyLineItem>()
                {
                    new ShopifyLineItem()
                    {
                        Title    = "Click Keyboard",
                        Price    = 99.99,
                        Grams    = 600,
                        Quantity = 1,
                        TaxLines = new List <ShopifyTaxLine>()
                        {
                            new ShopifyTaxLine()
                            {
                                Price = 1.0,
                                Rate  = 0.01,
                                Title = "Keyboard tax"
                            }
                        }
                    }
                },
                TaxLines = new List <ShopifyTaxLine>()
                {
                    new ShopifyTaxLine()
                    {
                        Price = 6.0,
                        Rate  = 0.06,
                        Title = "State tax"
                    }
                }
            };

            request.AddJsonBody(new { order });

            //Make request
            await RequestEngine.ExecuteRequestAsync <ShopifyOrder>(_RestClient, request);
        }
Esempio n. 22
0
        public RootAction Create(ShopifyOrder orderRecord, bool validate = true)
        {
            var output = new RootAction();

            output.OrderAction            = BuildOrderPendingAction(orderRecord);
            output.PaymentAction          = BuildPaymentActions(orderRecord);
            output.RefundPaymentActions   = BuildRefundPaymentActions(orderRecord);
            output.AdjustmentMemoActions  = BuildRefundAdjustmentActions(orderRecord);
            output.ShipmentInvoiceActions = BuildShipmentInvoiceActions(orderRecord);

            output.ErrorCount        = orderRecord.ErrorCount;
            output.ExceedsErrorLimit = orderRecord.ExceedsErrorLimit();
            output.Ignore            = orderRecord.Ignore;


            if (validate)
            {
                _orderValidation.Validate(output.OrderAction);
                _paymentValidation.ValidatePayment(orderRecord, output.PaymentAction);

                foreach (var action in output.RefundPaymentActions)
                {
                    _paymentValidation.ValidateRefundPayment(orderRecord, action);
                }

                foreach (var action in output.ShipmentInvoiceActions)
                {
                    _fulfillmentStatusService.Validate(orderRecord, action);
                }

                foreach (var action in output.AdjustmentMemoActions)
                {
                    _memoValidationService.Validate(output, action);
                }
            }

            return(output);
        }
Esempio n. 23
0
 public static string LogDescriptor(this ShopifyOrder shopifyOrder)
 {
     return($"Shopify Order {shopifyOrder.ShopifyOrderNumber} " +
            $"({shopifyOrder.ShopifyOrderId})");
 }
        public async Task <IActionResult> ShopifyInvoiceEndpoint(
            [FromServices] InvoiceRepository invoiceRepository,
            [FromServices] InvoiceController invoiceController,
            [FromServices] IHttpClientFactory httpClientFactory,
            string storeId, string orderId, decimal amount, bool checkOnly = false)
        {
            var invoiceOrderId          = $"{ShopifyOrderMarkerHostedService.SHOPIFY_ORDER_ID_PREFIX}{orderId}";
            var matchedExistingInvoices = await invoiceRepository.GetInvoices(new InvoiceQuery()
            {
                OrderId = new[] { invoiceOrderId }, StoreId = new[] { storeId }
            });

            matchedExistingInvoices = matchedExistingInvoices.Where(entity =>
                                                                    entity.GetInternalTags(ShopifyOrderMarkerHostedService.SHOPIFY_ORDER_ID_PREFIX)
                                                                    .Any(s => s == orderId))
                                      .ToArray();

            var firstInvoiceStillPending =
                matchedExistingInvoices.FirstOrDefault(entity => entity.GetInvoiceState().Status == InvoiceStatus.New);

            if (firstInvoiceStillPending != null)
            {
                return(Ok(new
                {
                    invoiceId = firstInvoiceStillPending.Id,
                    status = firstInvoiceStillPending.Status.ToString().ToLowerInvariant()
                }));
            }

            var firstInvoiceSettled =
                matchedExistingInvoices.LastOrDefault(entity =>
                                                      new[] { InvoiceStatus.Paid, InvoiceStatus.Complete, InvoiceStatus.Confirmed }.Contains(
                                                          entity.GetInvoiceState().Status));

            var store = await _Repo.FindStore(storeId);

            var shopify             = store?.GetStoreBlob()?.Shopify;
            ShopifyApiClient client = null;
            ShopifyOrder     order  = null;

            if (shopify?.IntegratedAt.HasValue is true)
            {
                client = new ShopifyApiClient(httpClientFactory, shopify.CreateShopifyApiCredentials());
                order  = await client.GetOrder(orderId);

                if (string.IsNullOrEmpty(order?.Id))
                {
                    return(NotFound());
                }
            }

            if (firstInvoiceSettled != null)
            {
                //if BTCPay was shut down before the tx managed to get registered on shopify, this will fix it on the next UI load in shopify
                if (client != null && order?.FinancialStatus == "pending" &&
                    firstInvoiceSettled.Status != InvoiceStatus.Paid)
                {
                    await new OrderTransactionRegisterLogic(client).Process(orderId, firstInvoiceSettled.Id,
                                                                            firstInvoiceSettled.Currency,
                                                                            firstInvoiceSettled.Price.ToString(CultureInfo.InvariantCulture), true);
                    order = await client.GetOrder(orderId);
                }

                if (order?.FinancialStatus != "pending" && order?.FinancialStatus != "partially_paid")
                {
                    return(Ok(new
                    {
                        invoiceId = firstInvoiceSettled.Id,
                        status = firstInvoiceSettled.Status.ToString().ToLowerInvariant()
                    }));
                }
            }

            if (checkOnly)
            {
                return(Ok());
            }

            if (shopify?.IntegratedAt.HasValue is true)
            {
                if (string.IsNullOrEmpty(order?.Id) ||
                    !new[] { "pending", "partially_paid" }.Contains(order.FinancialStatus))
                {
                    return(NotFound());
                }

                //we create the invoice at due amount provided from order page or full amount if due amount is bigger than order amount
                var invoice = await invoiceController.CreateInvoiceCoreRaw(
                    new CreateInvoiceRequest()
                {
                    Amount   = amount < order.TotalPrice ? amount : order.TotalPrice,
                    Currency = order.Currency,
                    Metadata = new JObject {
                        ["orderId"] = invoiceOrderId
                    }
                }, store,
                    Request.GetAbsoluteUri(""), new List <string>() { invoiceOrderId });

                return(Ok(new { invoiceId = invoice.Id, status = invoice.Status.ToString().ToLowerInvariant() }));
            }

            return(NotFound());
        }
Esempio n. 25
0
 public static bool HasUnsyncedFulfillments(this ShopifyOrder order)
 {
     return(order.SoShipments().Any(x => x.ShopifyFulfillment == null));
 }
        /// <summary>
        /// A method that will throw an exception which looks like { errors: { "order" : [ "some error message" ] } }
        /// </summary>
        /// <returns></returns>
        public async Task ThrowArrayException()
        {
            var request = RequestEngine.CreateRequest("orders.json", Method.POST);

            //Creating an order with tax lines on both line items and the order will return an error
            var order = new ShopifyOrder()
            {
                CreatedAt = DateTime.UtcNow,
                LineItems = new List<ShopifyLineItem>()
                {
                    new ShopifyLineItem()
                    {
                        Title = "Click Keyboard",
                        Price = 99.99,
                        Grams = 600,
                        Quantity = 1,
                        TaxLines = new List<ShopifyTaxLine>()
                        {
                            new ShopifyTaxLine()
                            {
                                Price = 1.0,
                                Rate = 0.01,
                                Title = "Keyboard tax"
                            }
                        }
                    }
                },
                TaxLines = new List<ShopifyTaxLine>()
                {
                    new ShopifyTaxLine()
                    {
                        Price = 6.0,
                        Rate = 0.06,
                        Title = "State tax"
                    }
                }
            };

            request.AddJsonBody(new { order });

            //Make request
            await RequestEngine.ExecuteRequestAsync<ShopifyOrder>(_RestClient, request);
        }
Esempio n. 27
0
 public static bool DoesNotExceedErrorLimit(this ShopifyOrder order)
 {
     return(!order.ExceedsErrorLimit());
 }
Esempio n. 28
0
 public static bool ExceedsErrorLimit(this ShopifyOrder order)
 {
     return(order.ErrorCount >= SystemConsts.ErrorThreshold);
 }
Esempio n. 29
0
 public static decimal AcumaticaDebitMemosTotal(this ShopifyOrder order)
 {
     return(order.ShopifyRefunds
            .Where(x => x.DebitAdjustment > 0 && x.AcumaticaMemo != null)
            .Sum(x => x.AcumaticaMemo.AcumaticaAmount));
 }
Esempio n. 30
0
 public static string AcumaticaCustomerId(this ShopifyOrder order)
 {
     return(order.ExistsInAcumatica() ? order.SyncedSalesOrder().AcumaticaCustomer.AcumaticaCustomerId : null);
 }
Esempio n. 31
0
 public static bool HasInvoicedShipments(this ShopifyOrder order)
 {
     return(order.SoShipments().Any());
 }