Repository navigation
Releases
0.12.2
Ossie schema 0.2.0.dev0. Tested with dactopus-ossie-clickhouse 0.14.0,
dbt v2 (dbt-oss 2.0.11) and dbt v1 (dbt-core 1.11 with
dbt-clickhouse 1.10) on ClickHouse 26.9, the WooCommerce package also on
26.7.
The GA4 and Sensor.Community packages need dbt build --full-refresh
once: their incremental tables record their label from this release on,
and a table built by an earlier one records none, so its first
incremental run stops and asks for it. The Shopify and WooCommerce
packages need none: their tables keep the record 0.12.0 wrote.
Changed
- One settings guard for every package:
macros/settings.sql, the same
file in each, run on all models from the package'sdbt_project.yml
(+pre-hook,+post-hook), ahead of a model's own hooks on dbt v1 and
v2; it does nothing on a model that is not incremental. The variables
it guards aremeta.guarded_varsthere, with their defaults, and the
variables any run may change aremeta.free_vars. It replaces the
Shopify macrosshopify_settings,shopify_check_settingsand
shopify_save_settingsand the WooCommerce macros
woocommerce_settings,woocommerce_check_settings,
woocommerce_save_settingsandwoocommerce_check_built. The record
and the message stay as they were. - The incremental tables of the GA4 package (
events,sessions,
purchases) and of the Sensor.Community package (readings) record
ga4_source_idandsensor_community_source_id: a run with another
label stops before it reads or deletes a row, where the one-label tests
caught it after the run had rewritten rows. Their dbt user needs
ALTER MODIFY COMMENTon these tables. Their READMEs have a section,
Changing a setting. - A variable a later release starts to guard is read as its default from
a table whose record lacks it: only a deployment that set another value
builds anew. - The phrase of the message,
was not built with the settings of this run, is what a tool that deploys the packages can tell the stop by
(docs/deployment.md); a change of it will be in this changelog.
Added
tests/check_contracts.pyfails on a package with an incremental model
or a time zone that does not run the guard from itsdbt_project.yml,
on a copy ofmacros/settings.sqlthat differs, on a variable of
varsin neithermeta.guarded_varsnormeta.free_vars, on a
default there other than the one invars, and on atime_zoneor
source_idvariable that is not guarded.tests/check_settings.pyruns a package's build with another value of
each guarded variable and checks that the run stops with the message,
names that variable alone and leaves the tables as they were; that a
record without a variable reads it as its default; and that a full
refresh records the new values. The CI job of every package runs it in
place of steps of its own.
0.12.1
Ossie schema 0.2.0.dev0. Tested with dactopus-ossie-clickhouse 0.14.0,
dbt v2 (dbt-oss 2.0.11) and dbt v1 (dbt-core 1.11 with
dbt-clickhouse 1.10) on ClickHouse 26.9, the WooCommerce package also on
26.7.
Changed
- CI installs dactopus-ossie-clickhouse 0.14.0 from PyPI instead of 0.12.0 from
git. - The commerce model's instructions no longer tell an agent that a store
missing from a result has a zero for a ratio or an average, such as the
average order value or the refund rate: it has a zero count or sum there
and no ratio or average.
0.12.0
Ossie schema 0.2.0.dev0. Tested with dactopus-ossie-clickhouse 0.13.0
(the canon and the blind questions) and 0.12.0 (CI), dbt v2 (dbt-oss
2.0.11) and dbt v1 (dbt-core 1.11 with dbt-clickhouse 1.10) on
ClickHouse 26.9, the WooCommerce package also on 26.7. Needs
dbt build --full-refresh once.
order_lines, line_categories, line_brands and refunds of both
packages and of the commerce union gain a column: an incremental run
stops on the changed schema, and a deployment runs
dbt build --full-refresh once. The same full refresh records the
settings the new check below needs. No input table changes. Metric names
of the commerce model change.
Changed
-
orders,order_linesandrefundsof the Shopify and WooCommerce
packages built by an earlier release record no settings, so their
first incremental run stops with the message of the check below. The
full refresh this release needs for the new columns builds them anew
and records the settings, so onedbt build --full-refreshcovers
both. -
The dbt user needs
ALTER MODIFY COMMENTonorders,order_lines
andrefundsof both packages. The WooCommerce package needed it on
refundsalready. -
The 18 commerce metrics that read order lines, their categories and
brands, or refunds together withorders.in_sales_reportsare metrics
of those datasets, as the Ossie spec requires: it rejects an aggregate
over fields of two datasets, and its relational layer does not expose
the metrics of the model itself. A question names them
dataset.metric, and result columns are named so too. This breaks
saved questions, dashboards and agent prompts that ask for the old
names; the numbers are unchanged:Old New items_sold,items_net,line_revenue,items_returned,line_returned_amount,line_net_revenuethe same name on order_lines:order_lines.line_revenuecategory_items_sold,category_revenue,category_items_returned,category_returned_amount,category_net_revenuethe same name on line_categories:line_categories.category_revenuebrand_items_sold,brand_revenue,brand_items_returned,brand_returned_amount,brand_net_revenuethe same name on line_brands:line_brands.brand_revenuerefund_count,refunds_totalthe same name on refunds:refunds.refunds_totalThe model has no metrics of its own any more.
-
order_lines,line_categories,line_brandsandrefundscarry
in_sales_reports(Bool), the flag of the line's or refund's order
(orders.in_sales_reports), so that the metrics above count the rows
of one dataset. At Shopify it is true. At WooCommerce the packages
compute it from the order's status, time placed and payment and
completion dates, by the formula ofordersthat now sits in the
macroswoocommerce_report_timeandwoocommerce_in_sales_reports.
The commerce union lists the column too. -
orders.refund_rate,orders.average_order_value,
orders.items_per_orderandorders.repeat_order_sharedivide by
NULLIF(..., 0): a question that matches no counted order gets NULL,
where it divided by zero. -
tests/check_contracts.pyfails on a metric that reads fields of more
than one dataset.AGENTS.mdandCONTRIBUTING.mdstate the rule,
anddocs/commerce.mdlists the metrics by dataset. -
The model instructions said every metric but
orders.all_ordersand
orders.all_orders_totalcounts only the orders the store's sales
reports count. The metrics ofcustomerscount the orders the store's
customers report counts, which at WooCommerce includes an order on hold
that is not paid yet. The
instructions and the descriptions ofcustomerssay so;
CONTRIBUTING.mdandAGENTS.mdstate the rule: a dataset built from
orders says which orders it counts, in the model's terms, and then
names the store report that counts the same.
Added
- An incremental run of the Shopify and WooCommerce packages stops, before
it reads or deletes a row oforders,order_linesorrefunds, when
the variables that decide the values of the rows already built differ
from the ones the tables were built with.
Until now a changed variable rebuilt only the orders the run reread and
left the others as they were, a mixture that no test caught (the
one-label tests caught a new label, after the run had rewritten rows).
The message names the table, each differing variable with its old and
new value, and asks fordbt build --full-refreshonce. Guarded at
Shopify:shopify_timezone,shopify_source_id. At WooCommerce:
woocommerce_timezone,woocommerce_date_type,
woocommerce_excluded_statuses,woocommerce_order_statuses,
woocommerce_currency,woocommerce_price_decimals,
woocommerce_order_number_meta_key,woocommerce_source_id. The input
database, the table prefix and the lookback days are not guarded. - The values are kept in the comment of
orders,order_linesand
refunds, asbuilt with {...}(JSON, keys in alphabetical order),
written after a first build or a full refresh. At WooCommerce the
comment ofrefundsalso holds its sync position, and each macro
that writes the comment keeps the segments it does not own
(woocommerce_set_comment). The README of each package has a section,
Changing a setting. - Tests
order_lines_in_sales_reports_match_ordersand
refunds_in_sales_reports_match_ordersin both packages: no line or
refund has a flag different from its order's. At WooCommerce they warn
untilDACTOPUS_STRICT_TESTS=error, as the package's other tests that
compare two tables. line_categories.category_tree_items_sold,category_tree_revenue,
category_tree_items_returned,category_tree_returned_amountand
category_tree_net_revenue, and
product_categories.category_tree_product_count: the category metrics
over every row of the line or product, the categories above its own
included. Filtered by one category (category_path), they count the
category with its subcategories, each line or product once. The
descriptions advisedorder_lines.line_revenueor
products.product_countfiltered byline_categories.category_path
orproduct_categories.category_pathfor that: a filter on the many
side of a relationship, which dactopus-ossie-clickhouse answers and
the Ossie spec's relational and wide-table layers do not express. The
advice now names the new metrics;orders.average_order_value
filtered by a category keeps the old form, which has no other. The
tables do not change.
0.11.2
Ossie schema 0.2.0.dev0. Tested with dactopus-ossie-clickhouse 0.13.0,
the other versions as in 0.11.0.
Changed
- The instructions of the three models keep only the rules across their
datasets and fit in 2,300 characters (commercehad 8,367,
web_analytics3,683,iot2,870). dactopus-ossie-clickhouse puts
them into its MCP server's instructions, which Claude Code cut at
4,096 characters: an agent saw a quarter of thecommercerules there.
A rule about one dataset, field or metric moved to its description, and
one said twice is said once. The tables do not change and no rebuild
is needed.tests/check_contracts.pyfails on instructions over 2,300
characters.
0.11.1
Ossie schema 0.2.0.dev0. Tested with the same versions as 0.11.0.
Changed
- The descriptions of the three models name the source packages without
repository paths (sources/shopifyand the like). The tables do not
change and no rebuild is needed. - CI leaves a change of text alone out of the package and union jobs: a
dbt_project.ymlwhose only changed line is itsversion:, an entity
whosedescriptionandai_contextalone changed
(tests/reach.py). The validate job still runs on any change to an
entity. A release's version lines no longer run every package.
0.11.0
Ossie schema 0.2.0.dev0. Tested with dactopus-ossie-clickhouse 0.12.0,
dbt v2 (dbt-oss 2.0.11) and dbt v1 (dbt-core 1.11 with
dbt-clickhouse 1.10) on ClickHouse 26.9, the WooCommerce package also
on 26.7. The models write expressions in the sql form, which
dactopus-ossie-clickhouse reads since 0.11.0: an older version, or an
Ossie tool that reads only dialects, does not load them. No table
changes and no rebuild is needed.
Changed
- The models of the three domains write expressions as
expression: {sql: ...}instead of
expression: {dialects: [{dialect: ANSI_SQL, ...}]}, the form of the
apache/ossie examples and spec since apache/ossie#640. Reading it
needs dactopus-ossie-clickhouse 0.11.0 or newer. The numbers of the
models do not change and no rebuild is needed.
0.10.0
Ossie schema 0.2.0.dev0. Tested with dactopus-ossie-clickhouse 0.12.0,
dbt v2 (dbt-oss 2.0.8) and dbt v1 (dbt-core 1.11 with
dbt-clickhouse 1.10) on ClickHouse 26.9, the WooCommerce package also
on 26.7. The unions' views read the tables they add up with the rights
of the user who built them, so a user that reads a model needs SELECT
on the union's database alone; where row policies on those tables hide
rows from the reader, the numbers through a union change.
deployment.yml names the zone of the days of a package that fixes it.
No table changes and no rebuild is needed: a union changes on its next
build.
Added
-
zoneindeployment.yml: the zone of the days of a package that
fixes it in its model, so a deployment no longer has to be told it.
The Sensor.Community package declareszone: UTC; Shopify and
WooCommerce take the zone from the variable with the roletime_zone,
and GA4's days are in the property's zone; none of the three has the
key.zoneandtime_zoneexclude each other, and a union's file has
nozone.
tests/check_deployment.pyrequires an IANA name and counts in every
daily table the rows whose date is not the day of their time in
zone, with or without--time-zone, and fails on any such row or on
a--time-zonethat differs
(#60). -
tests/<source>/canon/andcanon_windows/for Shopify and
WooCommerce: the canonical tables ofentities/commerce.yaml(the
columns the model reads, in the order of the contracts) over
fixture.sql, and overfixture.sqlwithwindows.sql, one CSV file
a table, withtests/commerce/tables.sql, their DDL in standard SQL.
The questions and their expected rows are in
tests/<source>/questions.yaml.tests/run_canon.pyloads the files
into ClickHouse and asks the questions through dactopus-ossie-clickhouse,
so the model's numbers can be checked without dbt or the platform's raw
rows;--engine duckdbasks them through DuckDB's community extension
ossieinstead. Its 0.3.0 does not read the metrics of a dataset
(apache/ossie#591), so the model does not load there as it is:
tests/run_canon.pyloads a copy with them moved to the model's metrics. With that
copy, 72 of the 95 questions give the same
numbers, 19 are refused, and 4 differ: it leaves out the rows a
many-to-one relationship finds no match for (byproducts.status, the
lines of products theproductstable does not have; by
customers.first_order_month, the guests' orders).tests/export_canon.pywrites
the files from a built package, and CI fails when a build differs from
them.
Changed
- The distinct counts that pair
source_idwith the counted column
(orders.buyer_count,product_categories.product_count,
product_brands.product_count,sessions.users,
sessions.user_conversion_rate,readings.reporting_devices) join the
two:COUNT(DISTINCT source_id || '/' || CAST(customer_id AS VARCHAR)).
COUNT(DISTINCT source_id, customer_id)is not standard SQL, and DuckDB
rejects it. The numbers are unchanged. - The questions of
tests/shopify/check_numbers.pyand
tests/woocommerce/check_numbers.pymoved toquestions.yaml, with
their derivations as comments; the two scripts read it and need
pyyaml(uv runinstalls it). The questions and their numbers are
unchanged. - The example databases and labels in
docs/deployment.mdname what
the store is, not its platform: databasesmain_store,outlet_store,
wholesale_store, labelsusa_store,wholesale_store. - The unions' views read the tables of the stores, properties and
networks with the rights of the user who built them
(+sql_security: definer,+definer: CURRENT_USER). A user with
SELECTon a union's database reads its model without a grant on the
databases it adds up, and those stay closed to it. Queries through a
view go under the builder's row policies on those tables, no longer
the reader's: this changes the numbers of a deployment whose row
policies there hide rows from the reader. A union changes on its next
build
(Several stores, properties or networks).
0.9.0
Ossie schema 0.2.0.dev0. Tested with dactopus-ossie-clickhouse 0.12.0,
dbt v2 (dbt-oss 2.0.8) and dbt v1 (dbt-core 1.11 with
dbt-clickhouse 1.10) on ClickHouse 26.9, the WooCommerce package also
on 26.7. Several stores, properties or networks in one deployment: every
table starts with the label source_id, orders carries platform,
and the unions add up the tables of several databases. Every column has
a declared type, and some types change: an incremental run stops on the
changed schema, and a deployment runs dbt build --full-refresh once.
No input table changes.
Added
- Every table of every package has a first column
source_id, the
label of the store, property or network its rows come from: the
variablega4_source_id,shopify_source_id,woocommerce_source_id
orsensor_community_source_id,LowCardinality(String). The default
is the package's name (shopify); a label other than 1 to 64 of
a-z,0-9and_stops the build. A dbt test on every model fails
on a row of another label, as an incremental run after a new label
leaves, and names--full-refresh.deployment.ymlmaps the role
source_idto the variable, andtests/check_deployment.pyrequires
it. - The Ossie models have a field
source_idin every dataset. It comes
first in everyprimary_keyand on both sides of every relationship,
and every count of distinct values counts them within a label
(orders.buyer_count,product_categories.product_count,
product_brands.product_count,readings.reporting_devices,
sessions.users,sessions.user_conversion_rate): the tables of
several stores, each built with its own label, keep their orders and
customers apart. In one database the label is constant and every
number stays the same. Its description and synonyms (store, shop;
property, site; network) let an agent find it, and each model's
instructions say how to answer over several: for a store, property or
network the question names or describes, an agent lists the labels and
takes the one that names it (for a store, also the one store in a
currency the question names), and asks when none does; a question that
names none means all of them; identifiers repeat across them, so an
agent groups by one with itssource_id; "today" is the date where the
model is served, while each one's dates are in its own zone. GA4 users
count within a property and are not matched across properties, and a
sensor network's silent devices count from its own latest contact. ordershas a columnplatform,shopifyorwoocommerce, after
currency, and the commerce model a fieldorders.platform: an agent
over stores of both platforms finds which store a question about
"the Shopify store" means, and which platform's report rules apply to
a store. The unions carry it.- Unions:
unions/commerce,unions/web_analyticsandunions/iot, dbt
projects that add up the tables of several stores, properties or
networks, each built by its package into a database of its own under
its own label. A union writes a view of each dataset of the domain's
Ossie model,UNION ALLover the databases of
commerce_union_databases,web_analytics_union_databasesor
iot_union_databases, with the columns the model reads and their
types as a dbt contract. A commerce union takes Shopify and
WooCommerce stores alike. The build stops on a database whose column
types differ from the contract and on the union's own database among
those it adds up; its test fails when a label is in two databases.
deployment.ymlmaps the roleinput_databasesto the variable.
tests/check_contracts.pychecks the unions' contracts against the
Ossie models and the packages, thatsource_idcomes first in every
key and relationship of the Ossie models, that each package tests the
key of each dataset (Sensor.Community'sreadingswith
sensor_community_unique_key, which replaces the test
readings_one_per_sensor_time_measure), and that the copies of
macros/union.sqland of each package'smacros/freshness.sqlare
the same;tests/check_union.pychecks that each label's answers over
a union are its database's own.
Fixed
- WooCommerce: an incremental run over a table whose columns a release
changed stops before its pre-hooks delete a row. dbt's own check of
the columns comes after the hooks: the run stopped withorder_lines
andrefundsshort of the rows of its window,refundsempty on the
fixture. - WooCommerce: category and brand names (
line_categories.category,
category_path,line_brands.brandand the same fields of
product_categoriesandproduct_brands) are decoded from the HTML
escaping WordPress stores them with:Home & Garden, not
Home & Garden. No table changes: the next run rebuilds the
category and brand tables whole.
Changed
-
CI runs a job only when a file it reads changed (the filters in
ci.yml): a pull request that changes only documentation runs none,
one that changes one package runs that package's jobs and the unions
job. The Ossie models are validated together in a job of their own.
The one checkmainrequires isCI passed, which fails when a job
failed or was cancelled; a skipped job does not block a merge. -
CI runs on
ubuntu-24.04, notubuntu-latest, and keys the uv cache
byci.yml: before, the key was constant and the cache was never
refreshed. -
AGENTS.md keeps what an agent applies while writing and is not in
CONTRIBUTING.md: the rules ofsource_id, contracts and unions, the
model format, ClickHouse traits, which page a change ships with, and
the development setup. Layout, scope, the authoring rules and the
checks before a pull request are read from CONTRIBUTING.md, whose
canon rule gains the two details only AGENTS.md had: a source that
has less of a field still provides it when the meaning is the same,
and no canonical field goes in "for completeness". -
The README is split. Each package's guide (loading, settings, known
differences from the source's own reports) issources/<source>/README.md;
what each Ossie model answers and its limits isdocs/<domain>.md;
the packages in a dbt project, labels, time zones, serving and unions
aredocs/deployment.md; layout, what a source package is, out of
scope and the authoring rules are in CONTRIBUTING.md. The README keeps
the overview, one quick start and versioning. Notes on how the
packages were checked against test stores, and the migration note for
snapshots loaded before 0.5.1, are gone from the guides: the checked
numbers are stated, the history is this changelog. The install
recipes take dactopus-ossie-clickhouse from PyPI. -
The commerce model's instructions: one deployment can hold several
stores, under their labels, in different currencies. An agent asks
every amount byorders.currency, answers in the one currency or in
each, and never adds up two; amounts of customers go by
customers.source_id.orders.currencyandcustomers.net_amount
say the same. A customer of two stores counts in each. -
README, Known differences from WooCommerce Analytics: buyers in a
month, where the reports also count a customer with only a refund. -
Every package declares the type of each column it writes, a dbt
contract inmodels/schema.yml, and a build stops on any other. The
columns an Ossie model reads come first in each table, with the same
types in every package that serves the model: the tables of Shopify
and WooCommerce add up withUNION ALL.tests/check_contracts.py
checks it in CI. No value changes; these types do:- Amounts are
Decimal(38, 8)and never NULL:orders.total,
subtotal,discount_total,shipping_total,tax_total,
refunded_total,net_total;customers.net_total;line_total
andreturned_amountoforder_lines,line_categoriesand
line_brands;refunds.refunded_amount;sales_events.amount.
Shopify's wereDecimal(18, 4)(customers.net_total
Decimal(38, 4)), and Shopify'sorder_lines.discount_total
follows; WooCommerce's wereNullable(Decimal(38, 8)), all but
orders.refunded_total. orders.customer_idisNullable(Int64),customers.customer_id
Int64: Shopify's wereNullable(UInt64)andUInt64,
WooCommerce'sorders.customer_idInt64.- Shopify's quantities are
Int64:orders.item_quantity;
quantityandcurrent_quantityoforder_lines,
line_categoriesandline_brands. They wereUInt32and
UInt64. - WooCommerce's
orders.order_time,refunds.refund_timeand
sales_events.event_timeareDateTime('UTC'), not
DateTime64(6, 'UTC'): WooCommerce keeps whole seconds. - Flags are
Bool:orders.is_cancelledand
customers.second_order_within_*_days(Nullable(Bool)) of both
packages, WooCommerce'sorders.in_sales_reportsandis_directof
line_categories,product_categoriesand
product_categories_all. They wereUInt8. - Shopify's
order_lines.titleisString, notNullable(String).
The columns of every table come in a new order, the model's first.
Withsource_id(Added), every package runs once with
--full-refreshin place of the next incremental run, which stops. - Amounts are
-
GA4:
on_schema_change: fail, as in the other packages; dbt requires
it of an incremental model with a contract. -
WooCommerce: an order or refund in another currency without a rate
the package knows now fails in its model, with a message that names
the README's Known limits, where before thenot_nulltests on its
amounts failed. -
The commerce model reads its
Boolflags alone, without= 1
(orders.is_cancelled,orders.in_sales_reports,
customers.second_order_within_*_daysand the
customers.second_order_rate_*_daysmetrics,is_directof
line_categoriesand `product...
0.8.0
Ossie schema 0.2.0.dev0. Tested with dactopus-ossie-clickhouse 0.12.0,
dbt v2 (dbt-oss 2.0.8) and dbt v1 (dbt-core 1.11 with
dbt-clickhouse 1.10) on ClickHouse 26.9. Customers for Shopify and
WooCommerce. orders gains columns, and the WooCommerce
orders.customer_id changes type: an incremental run stops on the
changed schema, and a deployment runs dbt build --full-refresh. No
input table changes.
Added
commerce.yaml:customers, one row per customer with an order the
store's report of new and returning customers counts, with
first_order_date,first_order_month(the cohort),
last_order_date,number_of_ordersandnet_total, what the
orders earned after refunds and cancellations (at WooCommerce, orders
on hold included, as the Customers report's total spend). Metrics
customer_count,net_amountandaverage_customer_value.orders
joins it oncustomer_id, so orders break down by cohort. A customer
record without such an order has no row, and the table holds no
email, name or address. Both packages build it fromorderson every
run.- Retention windows:
customers.second_order_within_30_days,
_60_days,_90_daysand_365_days, whether the second order came
within that many days of the first, and the metrics
second_order_rate_30_daystosecond_order_rate_365_days, the
share among customers whose window is over. A window stays empty
until its last day is before the day of the last load of orders
(loaded_atat Shopify,synced_atat WooCommerce, in the store's
time zone): it moves only when orders are loaded, so an
incremental run over unchanged input changes nothing. orders.days_since_previous_orderandmonths_since_first_order
(-1 on the first order, then calendar months, as Shopify's
months_since_first_purchase), between the dates the customer's
sequence goes by:processed_atat Shopify, the date placed at
WooCommerce, in the store's time zone. The metric
orders.average_days_between_ordersaverages the first.- Singular test
orders_numbered_in_sequencein both packages: each
customer's orders are numbered 1 to n. - Fixture cases for the customers and the windows
(tests/<source>/windows.sql,check_numbers.py --windows), and CI
steps that feed WooCommerce guest orders in parts and compare
customerswith a full refresh.
Changed
- Shopify: cancelled orders take their place in the customer's sequence
(customer_order_number,new_vs_repeat), as Shopify's report of new
and returning customers counts them: on the development store a
customer's only order, cancelled, is New, and the next one Returning.
Over the fixtureorders.repeat_order_sharegoes from 5/7 to 6/9. - WooCommerce: every order has a
customer_id, the customer WooCommerce
Analytics counts. A guest's order belongs to the account that has an
order billed to the same email, in any letter case (the smallest such
account where there are several); else to the guest, one per email,
numbered by the smallest id of their orders with a minus sign
(-112); a guest's order without an email is a customer of its own.
Guests are counted and numbered. orders.customersis renamedorders.buyer_count, no longer named
like a dataset. This breaks saved questions and dashboards that ask
for the old name.orders.repeat_order_share, a share of orders, gives up the synonyms
"repeat purchase rate" and "repeat rate": they usually ask about
customers and go to the windows' rates. An agent asked for a repeat
purchase rate now answers with a window and names it.- The README's known differences from Shopify's reports and from
WooCommerce Analytics follow the new numbering. On the development
store Shopify's customers, new and returning by month, each customer's
total sales and orders, and orders bymonths_since_first_purchase
equal the reports'. At WooCommerce the customers differ from Analytics
where an account's order is billed to another email: the model joins
that email's guest orders to the account. The README's commerce
section lists the customers' metrics. ROADMAP.md: Customers is done and leaves Next. Discount codes, which
code brought the revenue, is planned after it, under Later.
0.7.2
Ossie schema 0.2.0.dev0. Tested with dactopus-ossie-clickhouse 0.12.0,
dbt v2 (dbt-oss 2.0.8) and dbt v1 (dbt-core 1.11 with
dbt-clickhouse 1.10) on ClickHouse 26.9. The Shopify input gains a
column, and refunds and sales_events need the rebuild the first entry
describes; every other table builds the same as in 0.7.1.
Fixed
-
Shopify: a refund is dated by its
processedAt, the date Shopify's
sales reports count it on, instead of itscreatedAt
(#45).
The two are equal for a refund made in the admin. A refund imported
with a pastprocessedAt, as a store that moves its history to
Shopify records its returns, counted on the day of the import in
refunds.refund_dateandsales_events.event_date, and its month's
net sales were too high. Therefundsinput table has a new column,
processed_at, which a loader must deliver; the README's export
query reads it. A deployment adds it to the input, giving the refunds
already loaded theircreated_at:ALTER TABLE shopify_raw.refunds ADD COLUMN processed_at DateTime('UTC') DEFAULT created_at AFTER created_at; ALTER TABLE shopify_raw.refunds MATERIALIZE COLUMN processed_at SETTINGS mutations_sync = 1; ALTER TABLE shopify_raw.refunds MODIFY COLUMN processed_at REMOVE DEFAULT;
A store with imported refunds then exports its orders again from
before the first import, so that those refunds arrive with their
processedAt. Last,dbt build --full-refresh --select refunds+
rebuildsrefundsandsales_events: an incremental run keeps the
old dates of the refunds it does not reread, with no error. -
The descriptions of
refunds.refund_dateandrefund_timesay which
date they hold: the date the store's reports date the refund by, at
Shopify the date it was processed, for an imported refund its past
date and not the day it was recorded, asorder_datesays for orders. -
The Shopify and WooCommerce packages set
join_use_nulls = 0in their
queries. Their LEFT JOINs count on a missing match giving 0 (an order
without gift cards, a refund without lines); a server or profile that
sets it to 1 gave NULL totals and the build failed on
sales_events.amount.tests/profiles.ymlsets 1, so CI builds
against the setting the packages must not depend on.