public IEditablePricingContext createPricingContext(
      I_C_InvoiceLine invoiceLine, final int priceListId, final BigDecimal priceQty) {
    final org.compiere.model.I_C_Invoice invoice = invoiceLine.getC_Invoice();

    final boolean isSOTrx = invoice.isSOTrx();

    final int productId = invoiceLine.getM_Product_ID();

    int bPartnerId = invoice.getC_BPartner_ID();

    final Timestamp date = invoice.getDateInvoiced();

    final IEditablePricingContext pricingCtx =
        Services.get(IPricingBL.class)
            .createInitialContext(
                productId, bPartnerId, invoiceLine.getPrice_UOM_ID(), priceQty, isSOTrx);
    pricingCtx.setPriceDate(date);

    // 03152: setting the 'ol' to allow the subscription system to compute the right price
    pricingCtx.setReferencedObject(invoiceLine);

    pricingCtx.setM_PriceList_ID(priceListId);
    // PLV is only accurate if PL selected in header
    // metas: relay on M_PriceList_ID only, don't use M_PriceList_Version_ID
    // pricingCtx.setM_PriceList_Version_ID(orderLine.getM_PriceList_Version_ID());

    return pricingCtx;
  }
  @Override
  public IEditablePricingContext createPricingContext(final I_C_InvoiceLine invoiceLine) {
    final I_C_Invoice invoice = invoiceLine.getC_Invoice();
    final int priceListId = invoice.getM_PriceList_ID();

    final BigDecimal qtyInvoicedInPriceUOM = calculateQtyInvoicedInPriceUOM(invoiceLine);

    return createPricingContext(invoiceLine, priceListId, qtyInvoicedInPriceUOM);
  }
  private boolean addInvoice0(final I_C_Invoice invoice) {
    //
    // Skip not posted invoices, but warn the user
    if (!invoice.isPosted()) {
      loggable.addLog("@Error@: @C_Invoice_ID@ @Posted@=@N@: " + invoiceBL.getSummary(invoice));
      return false;
    }

    //
    // Tax declaration lines (one for each invoice tax record)
    final List<I_C_InvoiceTax> invoiceTaxes = invoiceDAO.retrieveTaxes(invoice);
    final Map<Integer, I_C_TaxDeclarationLine> taxId2taxDeclarationLine =
        new HashMap<>(invoiceTaxes.size());
    for (final I_C_InvoiceTax invoiceTax : invoiceTaxes) {
      final int taxId = invoiceTax.getC_Tax_ID();
      final I_C_TaxDeclarationLine taxDeclarationLine =
          createTaxDeclarationLine(invoice, invoiceTax);
      final I_C_TaxDeclarationLine taxDeclarationLineOld =
          taxId2taxDeclarationLine.put(taxId, taxDeclarationLine);
      Check.assumeNull(
          taxDeclarationLineOld,
          "More than one invoice tax line for {0}, taxId={1}",
          invoice,
          taxId);
    }

    //
    // Tax declaration accounting records
    final List<I_Fact_Acct> factAcctRecords =
        factAcctDAO
            .retrieveQueryForDocument(invoice)
            // fetch only those Fact_Acct records which are about taxes, i.e.
            .addNotEqualsFilter(I_Fact_Acct.COLUMN_C_Tax_ID, null) // C_Tax_ID is set
            .addEqualsFilter(I_Fact_Acct.COLUMN_Line_ID, null) // Line_ID is NOT set
            //
            .create()
            .list();
    for (final I_Fact_Acct factAcctRecord : factAcctRecords) {
      //
      // Link to Tax Declaration Line only if this Fact_Acct is about tax bookings. Which means:
      // * it's document level booking (Line_ID <= 0)
      // * we have a C_TaxDeclarationLine which has the same tax as this booking
      I_C_TaxDeclarationLine taxDeclarationLine = null;
      if (factAcctRecord.getLine_ID() <= 0) {
        final int taxId = factAcctRecord.getC_Tax_ID();
        taxDeclarationLine = taxId2taxDeclarationLine.get(taxId);
      }

      createTaxDeclarationAcct(taxDeclarationLine, factAcctRecord);
    }

    return true;
  }
  private void calculatePriceActual(final I_C_InvoiceLine invoiceLine, final int precision) {
    final BigDecimal discount = invoiceLine.getDiscount();
    final BigDecimal priceEntered = invoiceLine.getPriceEntered();

    BigDecimal priceActual;
    if (priceEntered.signum() == 0) {
      priceActual = priceEntered;
    } else {
      final int precisionToUse;
      if (precision >= 0) {
        precisionToUse = precision;
      } else {
        final I_C_Invoice invoice = invoiceLine.getC_Invoice();

        precisionToUse = invoice.getM_PriceList().getPricePrecision();
      }

      priceActual = subtractDiscount(priceEntered, discount, precisionToUse);
    }

    invoiceLine.setPriceActual(priceActual);
  }
  @Override
  public void updateLineNetAmt(final I_C_InvoiceLine line, final BigDecimal qtyEntered) {
    if (qtyEntered != null) {
      final Properties ctx = InterfaceWrapperHelper.getCtx(line);
      final I_C_Invoice invoice = line.getC_Invoice();
      final int priceListId = invoice.getM_PriceList_ID();

      //
      // We need to get the quantity in the pricing's UOM (if different)
      final BigDecimal convertedQty = calculateQtyInvoicedInPriceUOM(line);

      // this code has been borrowed from
      // org.compiere.model.CalloutOrder.amt
      final int stdPrecision = MPriceList.getStandardPrecision(ctx, priceListId);

      BigDecimal lineNetAmt = convertedQty.multiply(line.getPriceActual());

      if (lineNetAmt.scale() > stdPrecision) {
        lineNetAmt = lineNetAmt.setScale(stdPrecision, BigDecimal.ROUND_HALF_UP);
      }
      logger.info("LineNetAmt=" + lineNetAmt);
      line.setLineNetAmt(lineNetAmt);
    }
  }
  private final I_C_TaxDeclarationLine createTaxDeclarationLine(
      final I_C_Invoice invoice, final I_C_InvoiceTax invoiceTax) {
    final I_C_TaxDeclarationLine taxDeclarationLine = newTaxDeclarationLine();

    taxDeclarationLine.setAD_Org_ID(invoice.getAD_Org_ID());
    taxDeclarationLine.setIsManual(false);
    //
    taxDeclarationLine.setC_Invoice(invoice);
    taxDeclarationLine.setIsSOTrx(invoice.isSOTrx());
    taxDeclarationLine.setC_BPartner_ID(invoice.getC_BPartner_ID());
    taxDeclarationLine.setC_Currency_ID(invoice.getC_Currency_ID());
    taxDeclarationLine.setDateAcct(invoice.getDateAcct());
    taxDeclarationLine.setC_DocType_ID(invoice.getC_DocType_ID());
    taxDeclarationLine.setDocumentNo(invoice.getDocumentNo());
    //
    taxDeclarationLine.setC_Tax_ID(invoiceTax.getC_Tax_ID());
    taxDeclarationLine.setTaxBaseAmt(invoiceTax.getTaxBaseAmt());
    taxDeclarationLine.setTaxAmt(invoiceTax.getTaxAmt());

    save(taxDeclarationLine);

    return taxDeclarationLine;
  }
  @Override
  public boolean setTax(
      final Properties ctx, final org.compiere.model.I_C_InvoiceLine il, final String trxName) {
    int taxCategoryId = il.getC_TaxCategory_ID();
    if (taxCategoryId <= 0 && il.getM_Product_ID() > 0) {
      // NOTE: we can retrieve the tax category only if we have a product
      taxCategoryId = getC_TaxCategory_ID(il);
      il.setC_TaxCategory_ID(taxCategoryId);
    }

    if (il.getM_InOutLine_ID() <= 0) {
      logger.debug(il + "has M_InOutLine_ID=" + il.getM_InOutLine_ID() + ": returning");
      return false;
    }

    if (il.getM_Product_ID() <= 0) {
      // this might be the case if a descriptional il refers to an iol.
      logger.debug(il + "has M_Product_ID=" + il.getM_Product_ID() + ": returning");
      return false;
    }

    final I_M_InOut io = il.getM_InOutLine().getM_InOut();

    final I_C_Location locationFrom =
        Services.get(IWarehouseBL.class).getC_Location(io.getM_Warehouse());
    final int countryFromId = locationFrom.getC_Country_ID();

    final I_C_BPartner_Location locationTo =
        InterfaceWrapperHelper.create(io.getC_BPartner_Location(), I_C_BPartner_Location.class);

    final Timestamp shipDate = io.getMovementDate();
    final int taxId =
        Services.get(ITaxBL.class)
            .retrieveTaxIdForCategory(
                ctx,
                countryFromId,
                io.getAD_Org_ID(),
                locationTo,
                shipDate,
                taxCategoryId,
                il.getC_Invoice().isSOTrx(),
                trxName,
                false);

    if (taxId <= 0) {
      final I_C_Invoice invoice = il.getC_Invoice();
      throw new TaxNotFoundException(
          taxCategoryId,
          io.isSOTrx(),
          shipDate,
          locationFrom.getC_Location_ID(),
          locationTo.getC_Location_ID(),
          invoice.getDateInvoiced(),
          locationFrom.getC_Location_ID(),
          invoice.getC_BPartner_Location().getC_Location_ID());
    }

    final boolean taxChange = il.getC_Tax_ID() != taxId;
    if (taxChange) {
      logger.info("Changing C_Tax_ID to " + taxId + " for " + il);
      il.setC_Tax_ID(taxId);

      final I_C_Tax tax = il.getC_Tax();
      il.setC_TaxCategory_ID(tax.getC_TaxCategory_ID());
    }
    return taxChange;
  }
  @Override
  public int getC_TaxCategory_ID(final org.compiere.model.I_C_InvoiceLine invoiceLine) {
    // FIXME: we need to retrieve the C_TaxCategory_ID by using Pricing Engine

    if (invoiceLine.getC_Charge_ID() > 0) {
      return invoiceLine.getC_Charge().getC_TaxCategory_ID();
    }

    final I_C_Invoice invoice = invoiceLine.getC_Invoice();

    final IPriceListDAO priceListDAO = Services.get(IPriceListDAO.class);
    final Boolean processedPLVFiltering =
        null; // task 09533: the user doesn't know about PLV's processed flag, so we can't filter by
              // it

    if (invoice.getM_PriceList_ID() != 100) // FIXME use PriceList_None constant
    {
      final I_M_PriceList priceList = invoice.getM_PriceList();

      final I_M_PriceList_Version priceListVersion =
          priceListDAO.retrievePriceListVersionOrNull(
              priceList, invoice.getDateInvoiced(), processedPLVFiltering);
      Check.errorIf(
          priceListVersion == null, "Missing PLV for M_PriceList and DateInvoiced of {}", invoice);

      final int m_Product_ID = invoiceLine.getM_Product_ID();
      Check.assume(m_Product_ID > 0, "M_Product_ID > 0 for {}", invoiceLine);

      final I_M_ProductPrice productPrice =
          priceListDAO.retrieveProductPrice(priceListVersion, m_Product_ID);

      return productPrice.getC_TaxCategory_ID();
    }

    // Fallback: try getting from Order Line
    if (invoiceLine.getC_OrderLine_ID() > 0) {
      return invoiceLine.getC_OrderLine().getC_TaxCategory_ID();
    }

    // Fallback: try getting from Invoice -> Order
    if (invoiceLine.getC_Invoice().getC_Order_ID() > 0) {
      final Properties ctx = InterfaceWrapperHelper.getCtx(invoiceLine);
      final String trxName = InterfaceWrapperHelper.getTrxName(invoiceLine);

      final I_C_Order order =
          InterfaceWrapperHelper.create(
              ctx, invoiceLine.getC_Invoice().getC_Order_ID(), I_C_Order.class, trxName);

      final I_M_PriceList priceList = order.getM_PriceList();

      final I_M_PriceList_Version priceListVersion =
          priceListDAO.retrievePriceListVersionOrNull(
              priceList, invoice.getDateInvoiced(), processedPLVFiltering);
      Check.errorIf(
          priceListVersion == null, "Missing PLV for M_PriceList and DateInvoiced of {}", invoice);

      final int m_Product_ID = invoiceLine.getM_Product_ID();
      Check.assume(m_Product_ID > 0, "M_Product_ID > 0 for {}", invoiceLine);

      final I_M_ProductPrice productPrice =
          priceListDAO.retrieveProductPrice(priceListVersion, m_Product_ID);

      return productPrice.getC_TaxCategory_ID();
    }

    throw new AdempiereException(
        "@NotFound@ @C_TaxCategory_ID@ (" + "@C_InvoiceLine_ID@:" + invoiceLine + ")");
  }
Beispiel #9
0
  @Override
  public void createBankStatementLines(
      final I_C_BankStatement bankStatement, final I_C_PaySelection paySelection) {
    Check.errorIf(
        bankStatement.getC_BP_BankAccount_ID() != paySelection.getC_BP_BankAccount_ID(),
        "C_BankStatement {} with C_BP_BankAccount_ID={} and C_PaySelection {} with C_BP_BankAccount_ID={} need to have the same C_BP_BankAccount_ID",
        bankStatement,
        bankStatement.getC_BP_BankAccount_ID(),
        paySelection,
        paySelection.getC_BP_BankAccount_ID());

    // services
    final IPaySelectionDAO paySelectionDAO = Services.get(IPaySelectionDAO.class);
    final IInvoiceBL invoiceBL = Services.get(IInvoiceBL.class);
    final IBankStatementBL bankStatementBL = Services.get(IBankStatementBL.class);

    I_C_BankStatementLine bankStatementLine = null;
    int nextReferenceLineNo = 10;

    final List<I_C_PaySelectionLine> paySelectionLines =
        paySelectionDAO.retrievePaySelectionLines(paySelection, I_C_PaySelectionLine.class);
    for (final I_C_PaySelectionLine psl : paySelectionLines) {
      // Skip if already in a bank statement
      if (isInBankStatement(psl)) {
        continue;
      }

      // Skip if no invoice
      if (psl.getC_Invoice_ID() <= 0) {
        continue;
      }

      //
      // Create the bank statement line (if not already created)
      if (bankStatementLine == null) {
        bankStatementLine =
            InterfaceWrapperHelper.newInstance(I_C_BankStatementLine.class, paySelection);
        bankStatementLine.setAD_Org_ID(paySelection.getAD_Org_ID());
        bankStatementLine.setC_BankStatement(bankStatement);
        bankStatementLine.setIsMultiplePaymentOrInvoice(
            true); // we have a reference line for each invoice
        bankStatementLine.setIsMultiplePayment(true); // each invoice shall have it's own payment
        bankStatementLine.setC_Currency_ID(bankStatement.getC_BP_BankAccount().getC_Currency_ID());
        bankStatementLine.setValutaDate(paySelection.getPayDate());
        bankStatementLine.setDateAcct(paySelection.getPayDate());
        bankStatementLine.setStatementLineDate(paySelection.getPayDate());
        bankStatementLine.setReferenceNo(null); // no ReferenceNo at this level
        bankStatementLine.setC_BPartner(
            null); // no partner because we will have it on "line reference" level
        bankStatementLine.setStmtAmt(BigDecimal.ZERO); // will be updated at the end
        bankStatementLine.setTrxAmt(BigDecimal.ZERO); // will be updated at the end
        bankStatementLine.setChargeAmt(BigDecimal.ZERO);
        bankStatementLine.setInterestAmt(BigDecimal.ZERO);
        InterfaceWrapperHelper.save(bankStatementLine);
      }

      //
      // Create new bank statement line reference for our current pay selection line.
      final I_C_BankStatementLine_Ref bankStatementLineRef =
          InterfaceWrapperHelper.newInstance(I_C_BankStatementLine_Ref.class, bankStatementLine);
      bankStatementLineRef.setAD_Org_ID(bankStatementLine.getAD_Org_ID());
      bankStatementLineRef.setC_BankStatementLine(bankStatementLine);
      IBankStatementBL.DYNATTR_DisableBankStatementLineRecalculateFromReferences.setValue(
          bankStatementLineRef, true); // disable recalculation. we will do it at the end

      //
      // Set Invoice from pay selection line
      bankStatementLineRef.setC_BPartner_ID(psl.getC_BPartner_ID());
      final I_C_Invoice invoice = psl.getC_Invoice();
      bankStatementLineRef.setC_Invoice(invoice);
      bankStatementLineRef.setC_Currency_ID(invoice.getC_Currency_ID());

      //
      // Get pay schedule line amounts:
      final boolean isReceipt;
      if (invoiceBL.isCreditMemo(invoice)) {
        // SOTrx=Y, but credit memo => receipt=N
        isReceipt = !invoice.isSOTrx();
      } else {
        // SOTrx=Y => receipt=Y
        isReceipt = invoice.isSOTrx();
      }
      final BigDecimal factor = isReceipt ? BigDecimal.ONE : BigDecimal.ONE.negate();
      final BigDecimal linePayAmt = psl.getPayAmt().multiply(factor);
      final BigDecimal lineDiscountAmt = psl.getDiscountAmt().multiply(factor);

      // we store the psl's discount amount, because if we create a payment from this line, then we
      // don't want the psl's Discount to end up as a mere underpayment.
      bankStatementLineRef.setDiscountAmt(lineDiscountAmt);
      bankStatementLineRef.setTrxAmt(linePayAmt);
      bankStatementLineRef.setReferenceNo(psl.getReference());
      bankStatementLineRef.setLine(nextReferenceLineNo);

      //
      // Set Payment from pay selection line.
      // NOTE: In case the pay selection line does not already have a payment generated,
      // we are generating it now because it's the most convenient for the user.
      createPaymentIfNeeded(psl);
      bankStatementLineRef.setC_Payment_ID(psl.getC_Payment_ID());

      //
      // Save the bank statement line reference
      InterfaceWrapperHelper.save(bankStatementLineRef);
      nextReferenceLineNo += 10;

      //
      // Update pay selection line => mark it as reconciled
      linkBankStatementLine(psl, bankStatementLine, bankStatementLineRef);
    }

    //
    // Update Bank Statement Line's totals:
    if (bankStatementLine != null) {
      bankStatementBL.recalculateStatementLineAmounts(bankStatementLine);
    }
  }
Beispiel #10
0
  @Override
  public void updateFromInvoice(final org.compiere.model.I_C_PaySelectionLine psl) {
    final I_C_PaySelectionLine pslExt =
        InterfaceWrapperHelper.create(psl, I_C_PaySelectionLine.class);

    if (Services.get(IPaymentRequestBL.class).isUpdatedFromPaymentRequest(pslExt)) {
      return;
    }

    if (psl.getC_Invoice_ID() <= 0) {
      return; // nothing to do yet, but as C_PaySelectionLine.C_Invoice_ID is mandatory, we only
              // need to make sure this method is eventually called from a model interceptor
    }

    final IBPBankAccountDAO bpBankAccountDAO = Services.get(IBPBankAccountDAO.class);

    final Properties ctx = InterfaceWrapperHelper.getCtx(pslExt);

    final int partnerID = pslExt.getC_Invoice().getC_BPartner_ID();
    pslExt.setC_BPartner_ID(partnerID);

    final String paymentRule = pslExt.getPaymentRule();

    // task 09500 get the currency from the account of the selection header
    // this is safe because the columns are mandatory
    final int currencyID = pslExt.getC_PaySelection().getC_BP_BankAccount().getC_Currency_ID();

    final List<I_C_BP_BankAccount> bankAccts =
        bpBankAccountDAO.retrieveBankAccountsForPartnerAndCurrency(ctx, partnerID, currencyID);

    if (!bankAccts.isEmpty()) {
      int primaryAcct = 0;
      int secondaryAcct = 0;

      for (final I_C_BP_BankAccount account : bankAccts) {
        final int accountID = account.getC_BP_BankAccount_ID();
        if (accountID > 0) {
          if (account.getBPBankAcctUse().equals(X_C_BP_BankAccount.BPBANKACCTUSE_Both)) {
            secondaryAcct = accountID;
          } else if (account.getBPBankAcctUse().equals(paymentRule)) {
            primaryAcct = accountID;
            break;
          }
        }
      }
      if (primaryAcct != 0) {
        pslExt.setC_BP_BankAccount_ID(primaryAcct);
      } else if (secondaryAcct != 0) {
        pslExt.setC_BP_BankAccount_ID(secondaryAcct);
      }
    }

    // 08297: After trying to set the Reference from the payment request, fallback (if still empty)
    // to the Invoice's POReference
    final boolean trimWhitespaces = true;
    if (Check.isEmpty(pslExt.getReference(), trimWhitespaces)) {
      final I_C_Invoice invoice = pslExt.getC_Invoice();
      if (invoice == null) {
        return;
      }

      final String invoicePOReference = invoice.getPOReference();
      if (Check.isEmpty(invoicePOReference, trimWhitespaces)) {
        return;
      }
      pslExt.setReference(invoicePOReference);
    }
  }