/// <summary> /// Retrieves a customer discount item of the indicated type if it exists and creates one if not. /// </summary> /// <param name="salesLine">The sales line from which to find customer discount lines.</param> /// <param name="customerDiscountType">The customer discount type.</param> /// <param name="lineDiscountType">The line discount type.</param> /// <returns> /// The discount line. /// </returns> private static DiscountLine GetCustomerDiscountItem(SalesLine salesLine, CustomerDiscountType customerDiscountType, DiscountLineType lineDiscountType) { DiscountLine discount; var discounts = from d in salesLine.DiscountLines where d.DiscountLineType == lineDiscountType && d.CustomerDiscountType == customerDiscountType select d; // If the discount doesn't exist create a new one if (discounts.Count() == 0) { discount = new DiscountLine { DiscountLineType = lineDiscountType, CustomerDiscountType = customerDiscountType, }; salesLine.DiscountLines.Add(discount); } else { // otherwise select it. discount = discounts.First(); } return(discount); }
private static ProductPrice GetItemPrice(RequestContext requestContext, string itemId, string inventDimId, string unitOfMeasure, string customerAcctNumber) { SalesTransaction salesTransaction = new SalesTransaction { Id = Guid.NewGuid().ToString(), CustomerId = customerAcctNumber, }; SalesLine salesLine = new SalesLine() { LineId = Guid.NewGuid().ToString("N"), ItemId = itemId, InventoryDimensionId = inventDimId, SalesOrderUnitOfMeasure = unitOfMeasure, Quantity = 1m, }; salesTransaction.SalesLines.Add(salesLine); GetIndependentPriceDiscountServiceRequest priceRequest = new GetIndependentPriceDiscountServiceRequest(salesTransaction); GetPriceServiceResponse pricingServiceResponse = requestContext.Execute <GetPriceServiceResponse>(priceRequest); SalesLine resultLine = pricingServiceResponse.Transaction.SalesLines[0]; ProductPrice productPrice = GetProductPrice( resultLine.ItemId, resultLine.InventoryDimensionId, resultLine.BasePrice, resultLine.AgreementPrice, resultLine.AdjustedPrice, requestContext.GetChannelConfiguration().Currency); return(productPrice); }
public Task <bool> Handle(RegisterNewSalesLineCommand message, CancellationToken cancellationToken) { if (!message.IsValid()) { NotifyValidationErrors(message); return(Task.FromResult(false)); } var SalesLine = new SalesLine(Guid.NewGuid(), message.IdSales, message.IdDisc, "", message.Quantity, message.PriceUnit, message.SalesPrice, message.Cashback); if (_SalesRepository.GetById(SalesLine.IdSales) != null) { Bus.RaiseEvent(new DomainNotification(message.MessageType, "Ordem de Venda não existe")); return(Task.FromResult(false)); } if (_DiscMusicRepository.GetById(SalesLine.IdItem) != null) { Bus.RaiseEvent(new DomainNotification(message.MessageType, "O disco não existe")); return(Task.FromResult(false)); } _SalesLineRepository.Add(SalesLine); if (Commit()) { Bus.RaiseEvent(new SalesLineRegisteredEvent(SalesLine.Id, SalesLine.IdSales, SalesLine.IdItem, SalesLine.Quantity, SalesLine.PriceUnit, SalesLine.SalesPrice, SalesLine.Cashback)); } return(Task.FromResult(false)); }
/// <summary> /// Clear all customer discount lines. /// </summary> /// <param name="salesLine">The sales line.</param> /// <param name="deleteTotalCustomerDiscount">A value indicating whether the customer total discount should be deleted as well.</param> private static void ClearCustomerDiscountLines(SalesLine salesLine, bool deleteTotalCustomerDiscount) { if (salesLine == null) { throw new ArgumentNullException("salesLine"); } // Create a list for items to be removed var deleteList = new List <DiscountLine>(); foreach (DiscountLine discountLine in salesLine.DiscountLines) { if (discountLine.DiscountLineType == DiscountLineType.CustomerDiscount) { if (discountLine.CustomerDiscountType == CustomerDiscountType.TotalDiscount && deleteTotalCustomerDiscount) { deleteList.Add(discountLine); } else if (discountLine.CustomerDiscountType != CustomerDiscountType.TotalDiscount) { deleteList.Add(discountLine); } } } // Remove peridic discounts. foreach (DiscountLine discountLine in deleteList) { salesLine.DiscountLines.Remove(discountLine); } }
public Task <bool> Handle(UpdateSalesLineCommand message, CancellationToken cancellationToken) { if (!message.IsValid()) { NotifyValidationErrors(message); return(Task.FromResult(false)); } var SalesLine = new SalesLine(Guid.NewGuid(), message.IdSales, message.IdDisc, "", message.Quantity, message.PriceUnit, message.SalesPrice, message.Cashback); var existingSalesLine = _SalesLineRepository.GetById(SalesLine.Id); if (existingSalesLine != null && existingSalesLine.Id != SalesLine.Id) { if (!existingSalesLine.Equals(SalesLine)) { Bus.RaiseEvent(new DomainNotification(message.MessageType, "Ocorreu um erro ao salvar o item de venda")); return(Task.FromResult(false)); } } _SalesLineRepository.Update(SalesLine); if (Commit()) { Bus.RaiseEvent(new SalesLineUpdatedEvent(SalesLine.Id, SalesLine.IdSales, SalesLine.IdItem, SalesLine.DiscName, SalesLine.Quantity, SalesLine.PriceUnit, SalesLine.Cashback)); } return(Task.FromResult(false)); }
internal static void ClearDiscountLinesOfType(SalesLine salesLine, DiscountLineType?lineType) { if (lineType == null) { salesLine.DiscountLines.Clear(); return; } var remainingDiscounts = salesLine.DiscountLines.Where(l => l.DiscountLineType != lineType).ToList(); salesLine.DiscountLines.Clear(); foreach (var discount in remainingDiscounts) { salesLine.DiscountLines.Add(discount); } if (lineType == DiscountLineType.PeriodicDiscount) { salesLine.PeriodicDiscountPossibilities.Clear(); salesLine.QuantityDiscounted = 0; } if (lineType == DiscountLineType.CustomerDiscount) { salesLine.LineMultilineDiscOnItem = LineMultilineDiscountOnItem.None; } }
/// <summary> /// Update the discount items. /// </summary> /// <param name="saleItem">The item line that the discount line is added to.</param> /// <param name="discountItem">The new discount line to add.</param> internal static void UpdateDiscountLines(SalesLine saleItem, DiscountLine discountItem) { // Check if line discount is found, if so then update bool discountLineFound = false; foreach (var discLine in saleItem.DiscountLines) { if (discLine.DiscountLineType == DiscountLineType.CustomerDiscount) { // If found then update if ((discLine.DiscountLineType == discountItem.DiscountLineType) && (discLine.CustomerDiscountType == discountItem.CustomerDiscountType)) { discLine.Percentage = discountItem.Percentage; discLine.Amount = discountItem.Amount; discountLineFound = true; } } } // If line discount is not found then add it. if (!discountLineFound) { saleItem.DiscountLines.Add(discountItem); } if (discountItem.DiscountLineType == DiscountLineType.CustomerDiscount) { saleItem.ResetLineMultilineDiscountOnItem(); } saleItem.WasChanged = true; }
/// <summary> /// Splits a SalesLine into two sales lines in cases where a discount only applies to a portion of the quantity. /// </summary> /// <param name="salesLine">The line to split.</param> /// <param name="quantityNeeded">The quantity to split away from this line.</param> /// <returns>The new SalesLine containing the needed quantity.</returns> private SalesLine SplitLine(SalesLine salesLine, decimal quantityNeeded) { if (salesLine.Quantity < 0) { quantityNeeded *= -1; } // Create the duplicate sale line. SalesLine newLine = salesLine.Clone <SalesLine>(); newLine.Quantity = quantityNeeded; newLine.QuantityDiscounted = 0m; newLine.LineId = Guid.NewGuid().ToString("N"); newLine.OriginLineId = salesLine.OriginLineId; if (salesLine.LineManualDiscountAmount != decimal.Zero && salesLine.Quantity > 0) { newLine.LineManualDiscountAmount = this.priceContext.CurrencyAndRoundingHelper.Round((salesLine.LineManualDiscountAmount / salesLine.Quantity) * newLine.Quantity); salesLine.LineManualDiscountAmount -= newLine.LineManualDiscountAmount; } // Set the new quantity on the orgininal sale line item. salesLine.Quantity -= quantityNeeded; return(newLine); }
private static bool SetSalesInventory(RequestContext context, SalesLine salesLine, ItemAvailability itemAvailability, Dictionary <string, decimal> salesLineInventoryQuantities) { decimal salesLineInventoryQuantity = salesLineInventoryQuantities[salesLine.LineId]; if (itemAvailability == null) { var notification = new InventoryNotFoundNotification(salesLine.LineId); context.Notify(notification); } else { if (itemAvailability.AvailableQuantity < salesLineInventoryQuantity) { var notification = new InsufficientQuantityAvailableNotification(salesLine.LineId, salesLine.ItemId); context.Notify(notification); } salesLine.InventoryLocationId = itemAvailability.InventoryLocationId; itemAvailability.AvailableQuantity -= salesLineInventoryQuantity; return(true); } return(false); }
public mySale GetNewSale() { //Apenas com uma linha SalesLine line = new SalesLine() { LineNumber = 1, ItemCode = "ART1", ItemDescription = "Artigo cust", Quantity = 3, VATTax = 23, UnitPriceExcludedVAT = 100, Discount1 = 1, Discount2 = 2, Discount3 = 3, DiscountValue = 4, }; mySale mySale = new mySale() { FiscalYear = "2018", SectionCode = "1", DocTypeAbbrev = "FAT", EntityCode = 1, Date = DateTime.Now, ExpirationDate = DateTime.Now, CurrencyCode = "EUR", Lines = new List <SalesLine>() { line }, GetReportBytes = true, }; return(mySale); }
/// <summary> /// Gets maximum retail price from trade agreement. /// </summary> /// <param name="salesLine">The sales line.</param> /// <param name="context">The request context.</param> /// <returns>Maximum retail price from trade agreement.</returns> public decimal GetMaximumRetailPriceFromTradeAgreement(SalesLine salesLine, RequestContext context) { if (salesLine == null) { throw new ArgumentNullException("salesLine"); } decimal quantity = this.salesTransaction.ActiveSalesLines.Where(x => (x.ItemId == salesLine.ItemId) && (x.InventoryDimensionId == salesLine.InventoryDimensionId)).Sum(x => x.Quantity); if (quantity == decimal.Zero) { quantity = 1; } if (!salesLine.BeginDateTime.IsValidAxDateTime()) { salesLine.BeginDateTime = context.GetNowInChannelTimeZone(); } PriceResult priceResult = PricingEngine.GetActiveTradeAgreement( this.pricingDataManager, DiscountParameters.CreateAndInitialize(this.pricingDataManager), this.channelConfiguration.Currency, salesLine, quantity, this.customerId, this.priceGroup, salesLine.BeginDateTime); this.maxRetailPrice = priceResult.MaximumRetailPriceIndia; return(this.maxRetailPrice); }
/// <summary> /// Creates a sales line from the xml element. /// </summary> /// <param name="xmlItemElement">The sales line line xml element.</param> /// <param name="order">The sales order.</param> /// <param name="lineId">The sales line identifier.</param> /// <param name="invoiceId">The invoice identifier.</param> /// <param name="invoiceBeginDate">The invoice begin date.</param> /// <param name="context">The request context.</param> private static void ParseAndCreateSalesLine(XElement xmlItemElement, SalesOrder order, int lineId, string invoiceId, DateTimeOffset invoiceBeginDate, RequestContext context) { SalesLine lineItem = new SalesLine(); lineItem.LineId = lineId.ToString(); lineItem.RecordId = long.Parse(xmlItemElement.Attribute("RecId").Value); lineItem.ItemId = xmlItemElement.Attribute("ItemId").Value; lineItem.Description = xmlItemElement.Attribute("EcoResProductName").Value; lineItem.InventoryDimensionId = xmlItemElement.Attribute("InventDimId").Value; lineItem.ReturnInventTransId = xmlItemElement.Attribute("InventTransId").Value; lineItem.ReturnTransactionId = invoiceId; decimal quantityInvoiced = decimal.Parse(xmlItemElement.Attribute("Qty").Value); lineItem.Quantity = decimal.Negate(quantityInvoiced); lineItem.UnitOfMeasureSymbol = xmlItemElement.Attribute("SalesUnit").Value; lineItem.ReturnQuantity = lineItem.Quantity; lineItem.QuantityInvoiced = quantityInvoiced; lineItem.Price = decimal.Parse(xmlItemElement.Attribute("SalesPrice").Value); lineItem.LineManualDiscountPercentage = decimal.Parse(xmlItemElement.Attribute("DiscPercent").Value); lineItem.DiscountAmount = decimal.Parse(xmlItemElement.Attribute("DiscAmount").Value); lineItem.NetAmount = decimal.Parse(xmlItemElement.Attribute("LineAmount").Value); lineItem.TaxAmount = decimal.Parse(xmlItemElement.Attribute("LineAmountTax").Value); lineItem.PeriodicDiscount = Convert.ToDecimal(xmlItemElement.Attribute("PeriodicDiscount").Value); lineItem.PeriodicPercentageDiscount = Convert.ToDecimal(xmlItemElement.Attribute("PeriodicPercentageDiscount").Value); lineItem.LineDiscount = Convert.ToDecimal(xmlItemElement.Attribute("LineDscAmount").Value); lineItem.TotalDiscount = Convert.ToDecimal(xmlItemElement.Attribute("TotalDiscount").Value); lineItem.TotalPercentageDiscount = Convert.ToDecimal(xmlItemElement.Attribute("TotalPctDiscount").Value); lineItem.LineManualDiscountAmount = Convert.ToDecimal(xmlItemElement.Attribute("LineManualDiscountAmount").Value); lineItem.LineManualDiscountPercentage = Convert.ToDecimal(xmlItemElement.Attribute("LineManualDiscountPercentage").Value); // lineItem.SalesMarkup = decimal.Parse(detail.Attribute("SalesMarkup").Value); lineItem.SalesTaxGroupId = xmlItemElement.Attribute("TaxGroup").Value; lineItem.ItemTaxGroupId = xmlItemElement.Attribute("TaxItemGroup").Value; lineItem.BatchId = xmlItemElement.Attribute("InventBatchId").Value; lineItem.SerialNumber = xmlItemElement.Attribute("InventSerialId").Value; lineItem.BeginDateTime = invoiceBeginDate; lineItem.DeliveryMode = order.DeliveryMode; lineItem.RequestedDeliveryDate = order.RequestedDeliveryDate; lineItem.ShippingAddress = order.ShippingAddress.Clone <Address>(); lineItem.InventoryDimensionId = xmlItemElement.Attribute("InventDimensionId").Value; Utilities.SetUpVariantAndProduct(context, lineItem.InventoryDimensionId, lineItem.ItemId, lineItem); foreach (XElement discountDetail in xmlItemElement.Elements("Discounts").Elements("Discount")) { ParseAndCreateDiscountLine(discountDetail, lineItem); } // All taxable items need to use invoice date to have taxes calculated properly foreach (TaxableItem taxableItem in lineItem.ChargeLines) { taxableItem.BeginDateTime = invoiceBeginDate; } order.SalesLines.Add(lineItem); }
private static decimal AllocateLoyaltyDiscountLines(SalesLine salesLine, IEnumerable <DiscountLine> loyaltyDiscountLineList, RoundingRule roundingRule) { decimal loyaltyDiscountEffectiveAmount = decimal.Zero; decimal loyaltyDiscountPercentage = decimal.Zero; decimal grossAmountDiscountable = (salesLine.Price * salesLine.Quantity) - salesLine.PeriodicDiscount - salesLine.LineDiscount - salesLine.TotalDiscount; if (loyaltyDiscountLineList.Any() && grossAmountDiscountable != decimal.Zero) { // Round 1: amount off fist foreach (DiscountLine loyaltyLine in loyaltyDiscountLineList) { loyaltyDiscountEffectiveAmount += loyaltyLine.SetEffectiveAmountForAmountOff(grossAmountDiscountable - loyaltyDiscountEffectiveAmount, salesLine.Quantity, roundingRule); } // Round 2: percent off, plus percentage decimal grossAmountBase = grossAmountDiscountable - loyaltyDiscountEffectiveAmount; foreach (DiscountLine loyaltyLine in loyaltyDiscountLineList) { if (grossAmountDiscountable != loyaltyDiscountEffectiveAmount) { decimal maxDiscountAmount = grossAmountDiscountable - loyaltyDiscountEffectiveAmount; loyaltyDiscountEffectiveAmount += loyaltyLine.AddEffectiveAmountForPercentOff(grossAmountBase, maxDiscountAmount, roundingRule); } } loyaltyDiscountPercentage = (loyaltyDiscountEffectiveAmount / grossAmountDiscountable) * 100m; } salesLine.LoyaltyDiscountAmount = loyaltyDiscountEffectiveAmount; salesLine.LoyaltyPercentageDiscount = Math.Round(loyaltyDiscountPercentage, 2); return(loyaltyDiscountEffectiveAmount); }
private static decimal AllocateTotalDiscountLines(SalesLine salesLine, List <DiscountLine> totalDiscountItemList, RoundingRule roundingRule) { decimal totalDiscountEffectiveAmount = 0; decimal totalDiscountPercentage = 0; decimal grossAmountDiscountable = (salesLine.Price * salesLine.Quantity) - salesLine.PeriodicDiscount - salesLine.LineDiscount; if (totalDiscountItemList.Any() && grossAmountDiscountable != decimal.Zero) { // Round 1: amount off fist. foreach (DiscountLine totalLine in totalDiscountItemList) { totalDiscountEffectiveAmount += totalLine.SetEffectiveAmountForAmountOff(grossAmountDiscountable - totalDiscountEffectiveAmount, salesLine.Quantity, roundingRule); } // Round 2: percent off, plus percentage. decimal grossAmountBase = grossAmountDiscountable - totalDiscountEffectiveAmount; foreach (DiscountLine totalLine in totalDiscountItemList) { if (grossAmountDiscountable != totalDiscountEffectiveAmount) { decimal maxDiscountAmount = grossAmountDiscountable - totalDiscountEffectiveAmount; totalDiscountEffectiveAmount += totalLine.AddEffectiveAmountForPercentOff(grossAmountBase, maxDiscountAmount, roundingRule); } } totalDiscountPercentage = (totalDiscountEffectiveAmount / grossAmountDiscountable) * 100m; } salesLine.TotalDiscount = totalDiscountEffectiveAmount; salesLine.TotalPercentageDiscount = Math.Round(totalDiscountPercentage, 2); return(totalDiscountEffectiveAmount); }
/// <summary> /// Adds the specified SalesLine object to the collection of lines included in this group. /// </summary> /// <param name="line">The line item to add.</param> public void Add(SalesLine line) { if (line != null) { this.salesLines.Add(line); this.Quantity += line.Quantity; } }
/// <summary> /// Clears the line level delivery values. /// </summary> /// <param name="salesLine">The sales line.</param> private static void ClearLineLevelDeliveryValues(SalesLine salesLine) { if (salesLine != null) { salesLine.DeliveryMode = null; salesLine.ShippingAddress = null; salesLine.FulfillmentStoreId = null; } }
/// <summary> /// Populates the fields for total amount, total discount, and total taxes on the sales line. /// </summary> /// <param name="salesTransaction">The parent transaction for the sales line.</param> /// <param name="salesLine">The sales line to total.</param> /// <param name="salesRoundingRule">Delegate which can do sales rounding.</param> public static void CalculateLine(SalesTransaction salesTransaction, SalesLine salesLine, RoundingRule salesRoundingRule) { if (salesTransaction == null) { throw new ArgumentNullException("salesTransaction"); } CalculateLine(salesTransaction.BeginDateTime, salesTransaction.LineDiscountCalculationType, salesLine, salesRoundingRule, true); }
/// <summary> /// Calculates the specific reason code on an entity like sales line, tender line etc. /// </summary> /// <param name="request">The request.</param> /// <param name="sourceId">The source identifier.</param> /// <param name="tableRefType">The table identifier for the specific reason code.</param> /// <param name="refRelation">The first reference relation key corresponding to the entity and table.</param> /// <param name="refRelation2">The second reference relation key corresponding to the entity and table.</param> /// <param name="refRelation3">The third reference relation key corresponding to the entity and table.</param> /// <param name="requiredReasonCodes">The collection to which required reason codes are added.</param> /// <param name="reasonCodeRequirements">The required specific reason codes map.</param> /// <param name="presentReasonCodeLines">The collection with the already present reason code lines.</param> /// <param name="salesLine">The sales line when applicable.</param> private static void CalculateReasonCodesSpecificToEntity( CalculateRequiredReasonCodesServiceRequest request, string sourceId, ReasonCodeTableRefType tableRefType, string refRelation, string refRelation2, string refRelation3, IDictionary <string, ReasonCode> requiredReasonCodes, HashSet <ReasonCodeRequirement> reasonCodeRequirements, IEnumerable <ReasonCodeLine> presentReasonCodeLines, SalesLine salesLine) { GetReasonCodesByTableRefTypeDataRequest getReasonCodesByTableRefTypeDataRequest = new GetReasonCodesByTableRefTypeDataRequest(tableRefType, refRelation, refRelation2, refRelation3, QueryResultSettings.AllRecords); IEnumerable <ReasonCode> reasonCodes = request.RequestContext.Runtime.Execute <EntityDataServiceResponse <ReasonCode> >(getReasonCodesByTableRefTypeDataRequest, request.RequestContext).PagedEntityCollection.Results; reasonCodes = AddLinkedReasonCodes(reasonCodes, request.RequestContext); var triggeredReasonCodes = CalculateTriggeredReasonCodes(reasonCodes, presentReasonCodeLines, request.RequestContext); reasonCodes = reasonCodes.Union(triggeredReasonCodes).Distinct(); reasonCodes = AddLinkedReasonCodes(reasonCodes, request.RequestContext); foreach (var reasonCode in reasonCodes) { if (presentReasonCodeLines.Any(rc => string.Equals(rc.ReasonCodeId, reasonCode.ReasonCodeId, StringComparison.OrdinalIgnoreCase))) { continue; } bool entitySpecificApplicability = true; switch (tableRefType) { case ReasonCodeTableRefType.Item: entitySpecificApplicability = HasSalesLineSpecificApplicability(reasonCode, salesLine); break; } if (entitySpecificApplicability && ShouldReasonCodeBeApplied(reasonCode, request.SalesTransaction)) { var reasonCodeRequirement = new ReasonCodeRequirement() { ReasonCodeId = reasonCode.ReasonCodeId, SourceId = sourceId, TableRefTypeValue = (int)tableRefType, }; reasonCodeRequirements.Add(reasonCodeRequirement); requiredReasonCodes[reasonCode.ReasonCodeId] = reasonCode; } } }
/// <summary> /// Set the price or original price depending on if price is overridden or keyed-in. /// </summary> /// <param name="line">Sales line to set price on.</param> /// <param name="priceToSet">Price to set.</param> private static void SetPriceOnSalesLine(SalesLine line, decimal priceToSet) { if (line.IsPriceOverridden) { line.OriginalPrice = priceToSet; } else { line.Price = priceToSet; } }
private static bool IsMatchUnitOfMeasure(SalesLine line, PriceAdjustment adjustment) { bool isMatch = string.IsNullOrWhiteSpace(adjustment.UnitOfMeasure); if (!isMatch) { isMatch = string.Equals(adjustment.UnitOfMeasure, line.SalesOrderUnitOfMeasure, StringComparison.OrdinalIgnoreCase); } return(isMatch); }
internal static string GetUnitOfMeasure(SalesLine salesLine) { string unitOfMeasure = salesLine.SalesOrderUnitOfMeasure; if (string.IsNullOrWhiteSpace(unitOfMeasure)) { unitOfMeasure = salesLine.UnitOfMeasureSymbol ?? string.Empty; } return(unitOfMeasure); }
/// <summary> /// Calculate the manual line discount. /// </summary> /// <param name="transaction">The transaction receiving total discount lines.</param> /// <param name="saleItem">The sale item that contains the discount lines.</param> /// <param name="lineDiscountItem">The line discount amount to discount the transaction.</param> private void AddLineDiscount(SalesTransaction transaction, SalesLine saleItem, DiscountLine lineDiscountItem) { Item item = PriceContextHelper.GetItem(this.priceContext, saleItem.ItemId); bool isDiscountAllowed = item != null ? !item.NoDiscountAllowed : true; if (isDiscountAllowed) { saleItem.DiscountLines.Add(lineDiscountItem); SalesLineTotaller.CalculateLine(transaction, saleItem, d => this.priceContext.CurrencyAndRoundingHelper.Round(d)); } }
/// <summary> /// Attempts to apply a DiscountLine to a SalesLine that has a larger quantity than the required quantity, splitting the line if it is found. /// </summary> /// <param name="transaction">The current transaction containing the lines.</param> /// <param name="availableLines">The available line indices on the transaction.</param> /// <param name="quantityNeeded">The quantity needed for the DiscountLine.</param> /// <param name="discount">The DiscountLine and original quantity needed.</param> /// <param name="isReturn">True if it's return.</param> /// <param name="requiresExistingCompoundedDiscounts">A flag indicating whether it requires existing compounded discounts on the line to compound on top of.</param> /// <returns>True if a match was found and the discount was applied, false otherwise.</returns> private bool ApplyDiscountLineForLargerMatch( SalesTransaction transaction, HashSet <int> availableLines, ref decimal quantityNeeded, DiscountLineQuantity discount, bool isReturn, bool requiresExistingCompoundedDiscounts) { bool discountApplied = false; foreach (int x in availableLines.ToList().OrderBy(p => this.salesLines[p].Quantity)) { SalesLine salesLine = this.salesLines[x]; if (!IsQuantityMatchSalesOrReturn(isReturn, salesLine.Quantity)) { continue; } decimal lineQuantity = Math.Abs(salesLine.Quantity); if (lineQuantity > quantityNeeded) { if (discount.DiscountLine.ConcurrencyMode != ConcurrencyMode.Compounded || CanApplyCompoundedDiscount(this.salesLines[x].DiscountLines, discount.DiscountLine, requiresExistingCompoundedDiscounts)) { // Perform the split of this line SalesLine newLine = this.SplitLine(this.salesLines[x], quantityNeeded); // Add the new line to the transaction and to the available lines for discounts. Set the line number to the next available number. newLine.LineNumber = transaction.SalesLines.Max(p => p.LineNumber) + 1; transaction.SalesLines.Add(newLine); this.salesLines.Add(newLine); DiscountLine discountLine = discount.DiscountLine.Clone <DiscountLine>(); discountLine.SaleLineNumber = newLine.LineNumber; newLine.DiscountLines.Add(discountLine); newLine.QuantityDiscounted = quantityNeeded * Math.Sign(salesLine.Quantity); // If this is a compounding discount, add the new line to the available lines. if (discount.DiscountLine.ConcurrencyMode == ConcurrencyMode.Compounded) { availableLines.Add(this.salesLines.Count - 1); } discountApplied = true; quantityNeeded = 0; break; } } } return(discountApplied); }
/// <summary> /// Executes the workflow for a get price check for a product. /// </summary> /// <param name="request">The request.</param> /// <returns>The response.</returns> protected override PriceCheckResponse Process(PriceCheckRequest request) { ThrowIf.Null(request, "request"); ItemBarcode itemBarcode = null; if (string.IsNullOrEmpty(request.Barcode) && string.IsNullOrEmpty(request.ItemId)) { throw new DataValidationException(DataValidationErrors.Microsoft_Dynamics_Commerce_Runtime_ItemIdBarcodeMissing, "Either an item identifier or barcode is required."); } if (string.IsNullOrEmpty(request.ItemId)) { GetProductBarcodeDataRequest dataRequest = new GetProductBarcodeDataRequest(request.Barcode); itemBarcode = this.Context.Runtime.Execute <GetProductBarcodeDataResponse>(dataRequest, this.Context).Barcode; } SalesTransaction salesTransaction = new SalesTransaction() { Id = Guid.NewGuid().ToString(), CustomerId = request.CustomerAccountNumber, }; SalesLine salesLine = new SalesLine() { ItemId = request.ItemId, InventoryDimensionId = request.InventoryDimensionId ?? itemBarcode.InventoryDimensionId, SalesOrderUnitOfMeasure = request.UnitOfMeasureSymbol ?? itemBarcode.UnitId, Quantity = 1m, LineId = Guid.NewGuid().ToString() }; salesTransaction.SalesLines.Add(salesLine); GetIndependentPriceDiscountServiceRequest priceRequest = new GetIndependentPriceDiscountServiceRequest(salesTransaction); GetPriceServiceResponse pricingServiceResponse = this.Context.Execute <GetPriceServiceResponse>(priceRequest); SalesLine resultLine = pricingServiceResponse.Transaction.SalesLines[0]; ProductPrice productPrice = GetProductPrice( resultLine.ItemId, resultLine.InventoryDimensionId, resultLine.BasePrice, resultLine.TotalAmount, this.Context.GetChannelConfiguration().Currency); var productPrices = new List <ProductPrice> { productPrice }; return(new PriceCheckResponse(productPrices.AsPagedResult())); }
private static SalesLine ConstructSalesLine(string itemId, string lineId = "1") { SalesLine salesLine = new SalesLine(); salesLine.OriginalSalesOrderUnitOfMeasure = "ea"; salesLine.SalesOrderUnitOfMeasure = "ea"; salesLine.ItemId = itemId; salesLine.Quantity = 1; salesLine.UnitOfMeasureConversion = UnitOfMeasureConversion.CreateDefaultUnitOfMeasureConversion(); salesLine.LineId = lineId; return(salesLine); }
public void OnExecuting(Request request) { CreateSalesOrderServiceRequest createSalesOrderServiceRequest = request as CreateSalesOrderServiceRequest; SalesTransaction salesTransaction = createSalesOrderServiceRequest.Transaction; string returnTransactionId = ""; string returnStore = ""; string returnTerminalId = ""; SalesOrder returnSalesOrder = null; Dictionary <string, Dictionary <string, decimal> > payments = new Dictionary <string, Dictionary <string, decimal> >(); Dictionary <string, Dictionary <string, decimal> > returnPayments = new Dictionary <string, Dictionary <string, decimal> >(); if (salesTransaction != null && salesTransaction.IsReturnByReceipt) { SalesLine salesLine = salesTransaction.SalesLines.First(line => !string.IsNullOrEmpty(line.ReturnTransactionId)); // Find the orginal transaction id. returnTransactionId = salesLine.ReturnTransactionId; returnStore = salesLine.ReturnStore; returnTerminalId = salesLine.ReturnTerminalId; if (!String.IsNullOrEmpty(returnTransactionId)) { var getSalesOrderDetailsByTransactionIdServiceRequest = new GetSalesOrderDetailsByTransactionIdServiceRequest(returnTransactionId, SearchLocation.All); var getSalesOrderDetailsServiceResponse = request.RequestContext.Execute <GetSalesOrderDetailsServiceResponse>(getSalesOrderDetailsByTransactionIdServiceRequest); returnSalesOrder = getSalesOrderDetailsServiceResponse.SalesOrder; } if (!string.IsNullOrEmpty(returnStore) && !string.IsNullOrEmpty(salesTransaction.StoreId) && salesTransaction.StoreId != returnStore) { throw new CommerceException("Microsoft_Dynamics_Commerce_ReturnInDifferentStore", ExceptionSeverity.Warning, null, "Custom error") { LocalizedMessage = "Return in different store from original is not allowed.", LocalizedMessageParameters = new object[] { } }; } if (returnSalesOrder != null && salesTransaction != null) { buildPayments(salesTransaction, ref payments); buildPayments(returnSalesOrder, ref returnPayments); } if (!comparePaymentsWithReturnPayments(payments, returnPayments)) { throw new CommerceException("Microsoft_Dynamics_Commerce_ReturnPaymentInconsistent", ExceptionSeverity.Warning, null, "Custom error") { LocalizedMessage = "The payment methods or amounts of return are inconsistent with original.", LocalizedMessageParameters = new object[] { } }; } } }
private static ProductPrice ActivePriceFromSalesLine(long productId, SalesLine salesLine) { return(new ProductPrice { UnitOfMeasure = salesLine.SalesOrderUnitOfMeasure, ItemId = salesLine.ItemId, InventoryDimensionId = salesLine.InventoryDimensionId, BasePrice = salesLine.BasePrice, TradeAgreementPrice = salesLine.AgreementPrice, AdjustedPrice = salesLine.AdjustedPrice, ProductId = productId }); }
/// <summary> /// Gets the return reason code for the transaction or empty, if none. /// </summary> /// <param name="salesTransaction">The sales transaction to get the reason code from.</param> /// <param name="context">The request context.</param> /// <returns>The reason code for the transaction or empty if none.</returns> private static string GetReturnReasonCodeId(SalesTransaction salesTransaction, RequestContext context) { // transaction server expects only one reason code, so we just take it from the first line that has reason codes SalesLine firstLineWithReasonCode = salesTransaction.SalesLines.FirstOrDefault(sl => sl.ReasonCodeLines.Any()); GetReturnOrderReasonCodesDataRequest getReturnOrderReasonCodesDataRequest = new GetReturnOrderReasonCodesDataRequest(QueryResultSettings.AllRecords); ReadOnlyCollection <ReasonCode> returnOrderReasonCodes = context.Runtime.Execute <EntityDataServiceResponse <ReasonCode> >(getReturnOrderReasonCodesDataRequest, context).PagedEntityCollection.Results; ReasonCodeLine returnReasonCodeLine = firstLineWithReasonCode != null ? firstLineWithReasonCode.ReasonCodeLines.FirstOrDefault(reasonCodeLine => returnOrderReasonCodes.Any(returnOrderReasonCode => returnOrderReasonCode.ReasonCodeId == reasonCodeLine.ReasonCodeId)) : null; return((returnReasonCodeLine != null && !string.IsNullOrWhiteSpace(returnReasonCodeLine.ReasonCodeId)) ? returnReasonCodeLine.ReasonCodeId : null); }
private static bool IsAdjustmentActiveOnSalesLine( SalesLine line, PriceAdjustment adjustment, DateTimeOffset defaultDate) { var activeDate = line.SalesDate ?? defaultDate; return(InternalValidationPeriod.ValidateDateAgainstValidationPeriod( (DateValidationType)adjustment.DateValidationType, adjustment.ValidationPeriod, adjustment.ValidFromDate, adjustment.ValidToDate, activeDate)); }
private static void ResolveAndApplyPriceForSalesLine(SalesLine item, IEnumerable <PriceLine> itemPriceLines, ICurrencyOperations currencyAndRoundingHelper) { var agreementLine = itemPriceLines.OfType <TradeAgreementPriceLine>().FirstOrDefault(); var baseLine = itemPriceLines.OfType <BasePriceLine>().FirstOrDefault(); bool hasTradeAgreementPrice = agreementLine != null; bool hasBasePrice = baseLine != null; item.AgreementPrice = hasTradeAgreementPrice ? agreementLine.Value : 0m; item.BasePrice = hasBasePrice ? baseLine.Value : 0m; // use the trade agreement price if any, otherwise use the base price if (hasTradeAgreementPrice) { SetPriceOnSalesLine(item, item.AgreementPrice); item.TradeAgreementPriceGroup = agreementLine.CustPriceGroup; } else if (hasBasePrice) { SetPriceOnSalesLine(item, item.BasePrice); item.AgreementPrice = item.BasePrice; } else { SetPriceOnSalesLine(item, 0); } // now try to apply any price adjustments var adjustmentLines = itemPriceLines.OfType <PriceAdjustmentPriceLine>(); item.AdjustedPrice = PriceAdjustmentCalculator.CalculatePromotionPrice(adjustmentLines, item.Price); if (Math.Abs(item.AdjustedPrice) < Math.Abs(item.Price)) { SetPriceOnSalesLine(item, item.AdjustedPrice); item.TradeAgreementPriceGroup = null; } // round prices item.Price = currencyAndRoundingHelper.Round(item.Price); if (item.OriginalPrice.HasValue) { item.OriginalPrice = currencyAndRoundingHelper.Round(item.OriginalPrice.Value); } item.BasePrice = currencyAndRoundingHelper.Round(item.BasePrice); item.AgreementPrice = currencyAndRoundingHelper.Round(item.AgreementPrice); item.AdjustedPrice = currencyAndRoundingHelper.Round(item.AdjustedPrice); }