Anyone know if there's trickery involved in applyi...
# suitescript
s
Anyone know if there's trickery involved in applying a Payment to an Invoice via a Journal Entry (i.e. simulating the "Accept Payment" button on an invoice and using the Credit subtab selecting a journal entry with the amount?
I've tried just creating a CustomerPayment record, setting fields akin to what I think that accept payment screen does, but no luck.
Notably, when you do that [Accept Payment] through the UI with a journal as the payment instrument, no actual CustomerPayment record is created as far as I can tell - the journal just stands in for it.
m
Copy code
/**
   * Apply the generated Write Off Transaction against the original transactions it is writing off
   *
   * @param { object } lines
   * @param { number } writeOffTransactionId
   */
  function applyWriteOffToTransactions(lines, writeOffTransactionId) {
    const paymentRecord = record.create({
      type: record.Type.CUSTOMER_PAYMENT,
      defaultValues: {
        entity: lines[0].entityId,
        currency: lines[0].currencyId,
      },
    });

    const [transactionsSublistId, writeOffTransactionSublistIds] =
      lines[0].writeOffType === constants.Enums.WriteOffType.INVOICES ? ["apply", "credit"] : ["credit", "apply"];

    lines.forEach((line) => {
      const amount = line.writeOffAmountForeignCurrency;
      selectTransactionOnPaymentRecord(paymentRecord, transactionsSublistId, line.transactionId, amount);
    });

    const total = lines.reduce((total, line) => total + line.writeOffAmountForeignCurrency, 0);
    selectTransactionOnPaymentRecord(paymentRecord, writeOffTransactionSublistIds, writeOffTransactionId, total);

    const id = paymentRecord.save();

    // Although we are using a Payment record to apply the credits against invoices, this should be a $0 application
    // and not result in the creation of an actual payment record. If this happens, it indicates that the generated
    // transaction does not balance against the amount being attempted to write off, for example due to rounding errors.
    // In that case, delete the payment record, and throw an error.
    if (id) {
      record.delete({ type: record.Type.CUSTOMER_PAYMENT, id });

      throw error.create({
        name: constants.ErrorCodes.CARS_ERROR_APPLYING_PAYMENT_RECORD_CREATED,
        message: constants.Strings.ERROR_APPLYING_PAYMENT_RECORD_CREATED_MESSAGE,
      });
    }
  }

  /**
   * Select a given transaction on either the apply/credit sublist of a payment record
   *
   * @param { import("N/record").Record } paymentRecord
   * @param { string } sublistId
   * @param { string|number } transactionId
   * @param { number } amount
   */
  function selectTransactionOnPaymentRecord(paymentRecord, sublistId, transactionId, amount) {
    const line = paymentRecord.findSublistLineWithValue({ sublistId, fieldId: "doc", value: String(transactionId) });

    if (line === -1) {
      throw error.create({
        name: constants.ErrorCodes.CARS_ERROR_APPLYING_CREDIT_TRANSACTION_NOT_FOUND,
        message: constants.Strings.ERROR_APPLYING_CREDIT_TRANSACTION_NOT_FOUND,
      });
    }

    paymentRecord.setSublistValue({ sublistId, line, fieldId: "apply", value: true });
    paymentRecord.setSublistValue({ sublistId, line, fieldId: "amount", value: amount });
  }
❤️ 3
s
Thanks @michoel - I was also setting a bunch of other fields - I'll try to reduce it to just what you're showing to see if that goes more smoothly.
🙏 1
Reducing things down to just mucking with apply and amount fields seemed to work. Thanks again @michoel!