I can suggest two approaches please try to implement:
The RowPersisting event captures the original tax details before any modifications
The RowPersisted event restores and updates the taxes after the main processing is complete
First Solution:
// Adjust taxes right before the Sales Order is persisted
protected void _(Events.RowPersisting<SOOrder> e)
{
if (e.Row == null) return;
SOOrder order = e.Row;
// Access the Taxes cache and adjust details
PXCache taxCache = Base.Caches[typeof(SOTaxTran)];
foreach (SOTaxTran tax in taxCache.Cached)
{
if (tax.TaxID == "SHOPIFY-TAX")
{
tax.CuryTaxAmt += 5; // Example adjustment
taxCache.Update(tax);
}
}
}
// Optionally handle actions after persist
protected void _(Events.RowPersisted<SOOrder> e, PXRowPersistedEventArgs args)
{
if (e.Row == null || args.TranStatus != PXTranStatus.Completed) return;
SOOrder order = e.Row;
// Log or perform additional adjustments post-persist
PXTrace.WriteInformation($"Order {order.OrderNbr} persisted successfully with adjusted taxes.");
}
}
OR try with below mentioned scenario:
Second Solution:
#region Override Events
protected virtual void _(Events.RowPersisting<SOOrder> e)
{
if (e.Row == null) return;
// Store original tax details before they get modified
StoreTaxDetails(e.Row);
}
protected virtual void _(Events.RowPersisted<SOOrder> e, PXRowPersisted baseHandler)
{
if (e.Row == null || e.TranStatus != PXTranStatus.Open) return;
if (e.Operation == PXDBOperation.Insert || e.Operation == PXDBOperation.Update)
{
RestoreAndUpdateTaxes(e.Row);
}
}
#endregion
#region Methods
private const string ORIGINAL_TAXES_KEY = "OriginalTaxDetails";
private void StoreTaxDetails(SOOrder order)
{
if (order?.TaxDetails == null || !order.TaxDetails.Any()) return;
// Deep clone the tax details to preserve them
var originalTaxes = order.TaxDetails.Select(tax => new SOTaxDetail
{
TaxID = tax.TaxID,
TaxRate = tax.TaxRate,
TaxAmount = tax.TaxAmount,
TaxableAmount = tax.TaxableAmount
// Add other relevant fields
}).ToList();
// Store in graph state
Base.ProviderState[ORIGINAL_TAXES_KEY] = originalTaxes;
}
private void RestoreAndUpdateTaxes(SOOrder order)
{
var originalTaxes = Base.ProviderState[ORIGINAL_TAXES_KEY] as List<SOTaxDetail>;
if (originalTaxes == null || !originalTaxes.Any()) return;
// Clear existing taxes
var taxesCache = Base.Taxes.Cache;
var existingTaxes = Base.Taxes.Select().RowCast<SOTaxTran>().ToList();
foreach (var existingTax in existingTaxes)
{
taxesCache.Delete(existingTax);
}
// Insert original taxes
foreach (var originalTax in originalTaxes)
{
var newTaxTran = new SOTaxTran
{
TaxID = originalTax.TaxID,
TaxRate = originalTax.TaxRate,
CuryTaxAmt = originalTax.TaxAmount,
CuryTaxableAmt = originalTax.TaxableAmount
// Set other necessary fields
};
taxesCache.Insert(newTaxTran);
}
// Force cache persistence
taxesCache.Persist(PXDBOperation.Insert);
// Recalculate document totals if needed
Base.Document.Cache.MarkUpdated(order);
}
#endregion
}
// Usage in your bucket import:
public override async Task SaveBucketImport(SPSalesOrderBucket bucket, IMappedEntity existing,
string operation, CancellationToken cancellationToken = default)
{
MappedOrder obj = bucket.Order;
// Store original tax details before any processing
var originalTaxDetails = obj.Local.TaxDetails?.ToList();
// Proceed with standard processing
await base.SaveBucketImport(bucket, existing, operation, cancellationToken);
// After base processing, ensure taxes are correct
if (originalTaxDetails?.Any() == true)
{
var graph = PXGraph.CreateInstance<SOOrderEntry>();
var orderExt = graph.GetExtension<SOOrderEntryExt>();
var order = graph.Document.Search<SOOrder.orderNbr>(
obj.Local.OrderNbr,
obj.Local.OrderType
).FirstOrDefault();
if (order != null)
{
// Update the order with original tax details
graph.ProviderState[SOOrderEntryExt.ORIGINAL_TAXES_KEY] = originalTaxDetails;
graph.Document.Update(order);
graph.Actions.PressSave();
}
}