Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@

target/
target-base/
dbt_packages/
dbt_modules/
logs/
Expand Down
8 changes: 7 additions & 1 deletion models/customer_segments.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ SELECT
customer_id,
number_of_orders,
customer_lifetime_value,
net_customer_lifetime_value,
CASE
WHEN number_of_orders > 10 THEN 'Frequent Buyer'
WHEN number_of_orders BETWEEN 5 AND 10 THEN 'Occasional Buyer'
Expand All @@ -12,5 +13,10 @@ SELECT
WHEN customer_lifetime_value > 4000 THEN 'High Value'
WHEN customer_lifetime_value BETWEEN 1500 AND 4000 THEN 'Medium Value'
ELSE 'Low Value'
END AS value_segment
END AS value_segment,
CASE
WHEN net_customer_lifetime_value > 4000 THEN 'High Value'
WHEN net_customer_lifetime_value BETWEEN 1500 AND 4000 THEN 'Medium Value'
ELSE 'Low Value'
END AS net_value_segment
FROM {{ ref('customers') }}
10 changes: 8 additions & 2 deletions models/customers.sql
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,17 @@ customer_payments as (

select
orders.customer_id,
sum(amount)::bigint as total_amount
sum(amount)::bigint as gross_amount, -- Includes coupon amount
sum(amount - coupon_amount)::bigint as net_amount, -- Excludes coupon amount

from payments

left join orders on
payments.order_id = orders.order_id
and orders.status = 'completed'

where payments.amount is not null -- Exclude incomplete payments
and payments.amount > 0 -- Exclude negative amounts

group by orders.customer_id

Expand All @@ -54,7 +59,8 @@ final as (
customer_orders.first_order,
customer_orders.most_recent_order,
customer_orders.number_of_orders,
customer_payments.total_amount as customer_lifetime_value
customer_payments.gross_amount as customer_lifetime_value, -- Gross CLV
customer_payments.net_amount as net_customer_lifetime_value -- Net CLV

from customers

Expand Down
31 changes: 31 additions & 0 deletions models/finance_revenue.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
with payments as (
select * from {{ ref('stg_payments') }}
),

payments_revenue as (
select
order_id,
sum(amount) as gross_revenue,
sum(amount - coupon_amount) as net_revenue
from payments
group by order_id
),

orders as (
select * from {{ ref('stg_orders') }}
),

final as (
select
orders.order_id,
orders.customer_id,
orders.order_date,
orders.status,
payments_revenue.gross_revenue,
payments_revenue.net_revenue
from orders
left join payments_revenue
on orders.order_id = payments_revenue.order_id
)

select * from final
77 changes: 72 additions & 5 deletions models/schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ version: 2

models:
- name: customers
description: This table has basic information about a customer, as well as some derived facts based on a customer's orders
description: This table has basic information about a customer, as well as some derived facts based on a customer's orders and payments, including both gross and profit-based customer lifetime value metrics

columns:
- name: customer_id
Expand All @@ -26,33 +26,57 @@ models:
- name: number_of_orders
description: Count of the number of orders a customer has placed

- name: customer_lifetime_value
description: Total value of a customer's orders including coupon amounts

- name: net_customer_lifetime_value
description: Total value of a customer's orders excluding coupon amounts

- name: total_order_amount
description: Total value (AUD) of a customer's orders

- name: customer_segments
description: This table categorizes customers based on their ordering behavior and value to the company, using derived metrics from their order history.
description: This table categorizes customers based on their ordering behavior and value to the company, using derived metrics from their order history and payment information.

columns:
- name: customer_id
description: This is a unique identifier for a customer.
tests:
- unique
- not_null
- relationships:
to: ref('customers')
field: customer_id

- name: number_of_orders
description: Count of the number of orders a customer has placed.
tests:
- not_null

- name: customer_lifetime_value
description: Total value (in currency) of all orders placed by a customer over their lifetime.
description: Total value of all orders including coupon amounts.

- name: net_customer_lifetime_value
description: Total value of all orders excluding coupon amounts.

- name: order_frequency_segment
description: Categorization of customers based on how frequently they place orders.
tests:
- not_null
- accepted_values:
values: ['Frequent Buyer', 'Occasional Buyer', 'Rare Buyer']

- name: value_segment
description: Categorization of customers based on the monetary value they bring to the company.
description: Categorization of customers based on the gross monetary value they bring to the company.
tests:
- accepted_values:
values: ['High Value', 'Medium Value', 'Low Value']
values: ['High Value', 'Medium Value', 'Low Value']

- name: net_value_segment
description: Categorization of customers based on the profit-based monetary value they bring to the company.
tests:
- accepted_values:
values: ['High Value', 'Medium Value', 'Low Value']

- name: customer_order_pattern
description: This table provides detailed insights into the ordering patterns of customers, including the frequency and recency of their orders.
Expand Down Expand Up @@ -130,3 +154,46 @@ models:
description: Amount of the order (AUD) paid for by gift card
tests:
- not_null

- name: finance_revenue
description: This table provides financial metrics for each order, including both gross revenue (including coupons) and profit-based revenue (excluding coupons).

columns:
- name: order_id
description: This is a unique identifier for an order
tests:
- unique
- not_null
- relationships:
to: ref('stg_orders')
field: order_id

- name: customer_id
description: Foreign key to the customers table
tests:
- not_null
- relationships:
to: ref('customers')
field: customer_id

- name: order_date
description: Date (UTC) that the order was placed
tests:
- not_null

- name: status
description: Current status of the order
tests:
- not_null
- accepted_values:
values: ['placed', 'shipped', 'completed', 'return_pending', 'returned']

- name: gross_revenue
description: Total revenue including coupon amounts
tests:
- not_null

- name: net_revenue
description: Total revenue excluding coupon amounts
tests:
- not_null
8 changes: 8 additions & 0 deletions models/staging/schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,11 @@ models:
tests:
- accepted_values:
values: ['credit_card', 'coupon', 'bank_transfer', 'gift_card']
- name: amount
description: Amount in dollars (converted from cents)
tests:
- not_null
- name: coupon_amount
description: Amount of the payment that was paid using a coupon (in dollars)
tests:
- not_null
3 changes: 2 additions & 1 deletion models/staging/stg_payments.sql
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ renamed as (
payment_method,

-- `amount` is currently stored in cents, so we convert it to dollars
amount / 100 as amount
amount / 100 as amount,
(payment_method = 'coupon')::int * (amount / 100) as coupon_amount

from source

Expand Down
Loading