SAP Business One Sales Analysis Query

SQL queries to analyze sales by customer — with credit notes deducted for accurate net revenue.

OINV, ORIN, OCRD 4 min read

These are sample queries you can run on Manager Boost. Use them as-is, or edit and customize on our platform. Go custom or use our pre-built queries — you're in control.

Key Concepts

Why Include Credit Notes?

OINV alone overstates revenue. If a customer buys $50K but returns $10K, their real value is $40K. Credit notes (ORIN) must be subtracted for accurate analysis.

Excluding Tax

DocTotal includes VAT/tax. For product revenue analysis, always subtract VatSum to get net revenue — tax is pass-through, not real revenue.

UNION ALL Pattern

We combine OINV and ORIN using UNION ALL, with ORIN amounts negated. This creates a single dataset where credits subtract from invoices automatically when summed.

Available Fields Reference

OINV / ORIN (Documents)

DocEntry DocNum DocDate CardCode CardName DocTotal VatSum SlpCode CANCELED

OCRD (Customer)

CardCode CardName GroupCode SlpCode Territory

Top Customers (Simple)

Without returns — useful for quick checks but not accurate:

SQLMS SQL Server
SELECT TOP 20
    T0.CardCode,
    T0.CardName,
    COUNT(T1.DocNum) AS Invoices,
    SUM(T1.DocTotal - T1.VatSum) AS NetRevenue
FROM OCRD T0
INNER JOIN OINV T1 ON T0.CardCode = T1.CardCode
WHERE T1.CANCELED = 'N'
  AND YEAR(T1.DocDate) = YEAR(GETDATE())
GROUP BY T0.CardCode, T0.CardName
ORDER BY NetRevenue DESC
Sample Result
CardCodeCardNameInvoicesNetRevenue
C10045Acme Corp28156000.00

Limitation: Ignores returns. A customer with lots of credit notes will rank higher than they should.

Top Customers (With Returns)

UNION invoices and credit notes, subtract credits for true net revenue:

SQLMS SQL Server
SELECT TOP 20
    CardCode,
    CardName,
    SUM(CASE WHEN DocType = 'INV' THEN 1 ELSE 0 END) AS Invoices,
    SUM(CASE WHEN DocType = 'CRN' THEN 1 ELSE 0 END) AS CreditNotes,
    SUM(NetAmount) AS NetRevenue
FROM (
    -- Invoices (positive)
    SELECT T0.CardCode, T0.CardName, 'INV' AS DocType,
           (T1.DocTotal - T1.VatSum) AS NetAmount
    FROM OCRD T0
    INNER JOIN OINV T1 ON T0.CardCode = T1.CardCode
    WHERE T1.CANCELED = 'N'
      AND YEAR(T1.DocDate) = YEAR(GETDATE())
    
    UNION ALL
    
    -- Credit Notes (negative)
    SELECT T0.CardCode, T0.CardName, 'CRN' AS DocType,
           -(T1.DocTotal - T1.VatSum) AS NetAmount
    FROM OCRD T0
    INNER JOIN ORIN T1 ON T0.CardCode = T1.CardCode
    WHERE T1.CANCELED = 'N'
      AND YEAR(T1.DocDate) = YEAR(GETDATE())
) Combined
GROUP BY CardCode, CardName
ORDER BY NetRevenue DESC
Sample Result
CardCodeCardNameInvoicesCreditNotesNetRevenue
C10045Acme Corp282148500.00

Revenue Breakdown with Percentage

Each customer's share of total revenue:

SQLMS SQL Server
WITH CustomerSales AS (
    SELECT 
        CardCode,
        CardName,
        SUM(NetAmount) AS NetRevenue
    FROM (
        SELECT T0.CardCode, T0.CardName, (T1.DocTotal - T1.VatSum) AS NetAmount
        FROM OCRD T0 INNER JOIN OINV T1 ON T0.CardCode = T1.CardCode
        WHERE T1.CANCELED = 'N' AND YEAR(T1.DocDate) = YEAR(GETDATE())
        UNION ALL
        SELECT T0.CardCode, T0.CardName, -(T1.DocTotal - T1.VatSum)
        FROM OCRD T0 INNER JOIN ORIN T1 ON T0.CardCode = T1.CardCode
        WHERE T1.CANCELED = 'N' AND YEAR(T1.DocDate) = YEAR(GETDATE())
    ) Combined
    GROUP BY CardCode, CardName
)
SELECT 
    CardCode,
    CardName,
    NetRevenue,
    ROUND(NetRevenue * 100.0 / SUM(NetRevenue) OVER(), 2) AS PctOfTotal
FROM CustomerSales
WHERE NetRevenue > 0
ORDER BY NetRevenue DESC
Sample Result
CardCodeCardNameNetRevenuePctOfTotal
C10045Acme Corp148500.0012.5

Customers with High Returns

Flag customers where credit notes exceed a threshold:

SQLMS SQL Server
SELECT 
    CardCode,
    CardName,
    Invoices,
    CreditNotes,
    GrossRevenue,
    Returns,
    GrossRevenue - Returns AS NetRevenue,
    ROUND(Returns * 100.0 / NULLIF(GrossRevenue, 0), 1) AS ReturnPct
FROM (
    SELECT 
        T0.CardCode,
        T0.CardName,
        SUM(CASE WHEN src = 'INV' THEN 1 ELSE 0 END) AS Invoices,
        SUM(CASE WHEN src = 'CRN' THEN 1 ELSE 0 END) AS CreditNotes,
        SUM(CASE WHEN src = 'INV' THEN Amt ELSE 0 END) AS GrossRevenue,
        SUM(CASE WHEN src = 'CRN' THEN Amt ELSE 0 END) AS Returns
    FROM (
        SELECT T0.CardCode, T0.CardName, 'INV' AS src, (T1.DocTotal - T1.VatSum) AS Amt
        FROM OCRD T0 INNER JOIN OINV T1 ON T0.CardCode = T1.CardCode
        WHERE T1.CANCELED = 'N' AND YEAR(T1.DocDate) = YEAR(GETDATE())
        UNION ALL
        SELECT T0.CardCode, T0.CardName, 'CRN' AS src, (T1.DocTotal - T1.VatSum) AS Amt
        FROM OCRD T0 INNER JOIN ORIN T1 ON T0.CardCode = T1.CardCode
        WHERE T1.CANCELED = 'N' AND YEAR(T1.DocDate) = YEAR(GETDATE())
    ) Data
    GROUP BY CardCode, CardName
) Summary
WHERE Returns > 0
ORDER BY ReturnPct DESC
Sample Result
CardCodeCardNameInvoicesCreditNotesGrossRevenueReturnsNetRevenueReturnPct
C10089Widget Inc15445000.008500.0036500.0018.9

Give your team answers in 3 seconds

No SQL. No training. Just plain English questions via SMS.