You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Cash Sale等文档发布后创建额外日记账分录?

How to Create a Second Journal Entry After Releasing Documents Like Cash Sale

Hey Eric, let’s tackle this problem step by step—you need to generate a second journal entry after the original one gets created when a document (like Cash Sale) is released, and you want to pull details from the original batch while supporting multiple document types. Here’s how to make it work:

1. Pick the Right Trigger Point (Where to Put Your Code)

The key here is to run your logic after the original journal entry is fully saved to the database. You’ve got two solid options depending on whether you want a per-document setup or a centralized solution:

Option A: Per-Document Graph Extensions (Targeted for Specific Docs)

For documents like Cash Sale, create an extension for their main graph (e.g., CashSaleEntry) and override the Release method. This ensures your code runs only after the base release logic finishes generating the original batch:

public class CashSaleEntry_Extension : PXGraphExtension<CashSaleEntry>
{
    public delegate void ReleaseDelegate();
    [PXOverride]
    public void Release(ReleaseDelegate baseMethod)
    {
        // First run the standard release logic to create the original journal entry
        baseMethod();

        // Grab the original batch that was just created
        GLBatch originalBatch = Base.BatchModule.Current;
        if (originalBatch != null)
        {
            // Generate your second journal entry here
            CreateSecondaryJournalEntry(originalBatch);
        }
    }

    private void CreateSecondaryJournalEntry(GLBatch originalBatch)
    {
        // 1. Create a new GLBatch, copying critical fields from the original
        GLBatch newBatch = new GLBatch
        {
            Module = originalBatch.Module,
            BranchID = originalBatch.BranchID,
            Description = $"Secondary Entry for Batch {originalBatch.BatchNbr}",
            Status = GLBatchStatus.Hold, // Set to Released if you want it auto-published
            OrigModule = originalBatch.OrigModule,
            OrigDocNbr = originalBatch.OrigDocNbr // Capture the original document reference
        };

        // Add the new batch to the graph's cache
        newBatch = Base.GLBatchModule.Insert(newBatch);
        Base.GLBatchModule.Update(newBatch);

        // 2. Pull original GLTran records and create matching entries for the new batch
        foreach (GLTran originalTran in PXSelect<GLTran, 
                Where<GLTran.batchNbr, Equal<Required<GLTran.batchNbr>>>>.Select(Base, originalBatch.BatchNbr))
        {
            GLTran newTran = new GLTran
            {
                BatchNbr = newBatch.BatchNbr,
                AccountID = originalTran.AccountID, // Adjust this if you need different accounts
                SubID = originalTran.SubID,
                TranAmt = originalTran.TranAmt * -1, // Example: Reverse the amount—tweak to your needs
                TranDesc = $"Secondary Line for {originalTran.TranDesc}"
            };

            Base.GLTranModule.Insert(newTran);
        }

        // 3. Save the new batch and transactions
        Base.Actions.PressSave();

        // Optional: Auto-release the new batch if needed
        // PXGraph.InstanceCreated<GLBatchMaint>(graph => graph.Release.Press());
    }
}

Option B: Centralized Logic (Supports Multiple Docs)

If you want to handle multiple document types (Cash Sale, AR Invoice, etc.) in one place, use an extension for GLBatchMaint and hook into the RowPersisted event. This triggers whenever a new GL batch is saved:

public class GLBatchMaint_Extension : PXGraphExtension<GLBatchMaint>
{
    protected void _(Events.RowPersisted<GLBatch> e)
    {
        // Only run when a new batch is inserted (skip updates/deletes)
        if (e.Operation != PXDBOperation.Insert) return;

        GLBatch originalBatch = e.Row;
        // Filter for modules you care about (SO = Cash Sale, AR = AR Invoice, etc.)
        if (new[] { "SO", "AR", "AP" }.Contains(originalBatch.OrigModule))
        {
            // Avoid infinite loops: add a custom boolean field to GLBatch (e.g., IsSecondary)
            if (originalBatch.GetExtension<GLBatchExt>().UsrIsSecondaryEntry == true) return;

            CreateSecondaryJournalEntry(originalBatch);
        }
    }

    private void CreateSecondaryJournalEntry(GLBatch originalBatch)
    {
        GLBatch newBatch = new GLBatch
        {
            Module = originalBatch.Module,
            BranchID = originalBatch.BranchID,
            Description = $"Secondary Entry for {originalBatch.OrigDocNbr}",
            Status = GLBatchStatus.Hold,
            OrigModule = originalBatch.OrigModule,
            OrigDocNbr = originalBatch.OrigDocNbr
        };

        // Mark this new batch as secondary to skip reprocessing
        newBatch.GetExtension<GLBatchExt>().UsrIsSecondaryEntry = true;

        newBatch = Base.Batch.Insert(newBatch);
        Base.Batch.Update(newBatch);

        // Add GLTran records as needed (same logic as the per-document example)
        foreach (GLTran originalTran in PXSelect<GLTran, 
                Where<GLTran.batchNbr, Equal<Required<GLTran.batchNbr>>>>.Select(Base, originalBatch.BatchNbr))
        {
            GLTran newTran = new GLTran
            {
                BatchNbr = newBatch.BatchNbr,
                AccountID = originalTran.AccountID,
                SubID = originalTran.SubID,
                TranAmt = originalTran.TranAmt * -1,
                TranDesc = $"Secondary Line: {originalTran.TranDesc}"
            };
            Base.Tran.Insert(newTran);
        }

        Base.Actions.PressSave();
    }
}

2. Key Tips to Avoid Headaches

  • Transaction Safety: Wrap your logic in a try-catch block to ensure if the secondary entry fails, the original document release doesn’t get stuck in a partial state.
  • Permissions: Make sure the user running the release has full access to create and modify GL batches and transactions.
  • Testing: Always test in a sandbox first—verify both the original and secondary entries are generated correctly across all document types you support.
  • Avoid Loops: The centralized approach needs a custom field to mark secondary batches, so your code doesn’t reprocess the entries it just created.

内容的提问来源于stack exchange,提问作者EricP.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 06:56:57