Skip to content
Draft
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 CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p

- `org`: new `Attribute` model with `Item.Attributes` for named item features such as color or size (EN 16931 BG-32). Attributes replace the previous practice of mapping `Item.Meta` into output formats — meta is internal-only data. Each attribute is identified by a `key` or `type` and holds exactly one of a `text`, `code`, `amount` (with optional `unit`), or `date` value. Standard keys cover physical properties of the item, dates, nutritional declarations, and CO2e emissions. Item attribute keys must be unique.
- `org`: `kj` (kilojoule) and `kcal` (kilocalorie) units.
- `org`: new `Package` model with `bill.Line.Packages` describing the physical packages used to pack and ship a line's items, with package type keys mapped to UN/ECE Recommendation 21 codes.

## [v0.502.2] - 2026-07-06

Expand Down
4 changes: 4 additions & 0 deletions bill/line.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ type Line struct {
// Breakdown of the line item for more detailed information. The sum of all lines
// will be used for the item price.
Breakdown []*SubLine `json:"breakdown,omitempty" jsonschema:"title=Breakdown"`
// Packages describe the physical packages or containers used to pack and
// ship the line's items, most useful in delivery documents.
Packages []*org.Package `json:"packages,omitempty" jsonschema:"title=Packages"`
// Result of quantity multiplied by the item's price (calculated)
Sum *num.Amount `json:"sum,omitempty" jsonschema:"title=Sum" jsonschema_extras:"calculated=true"`
// Discounts applied to this line
Expand Down Expand Up @@ -211,6 +214,7 @@ func normalizeLine(l *Line) {
l.Discounts = CleanLineDiscounts(l.Discounts)
l.Charges = CleanLineCharges(l.Charges)
l.Breakdown = CleanSubLines(l.Breakdown)
l.Packages = org.CleanPackages(l.Packages)
}

func normalizeSubLine(sl *SubLine) {
Expand Down
41 changes: 41 additions & 0 deletions data/rules/org.json
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,47 @@
}
]
},
{
"id": "GOBL-ORG-PACKAGE",
"object": "org.Package",
"subsets": [
{
"field": "key",
"subsets": [
{
"guard": "present",
"assert": [
{
"id": "GOBL-ORG-PACKAGE-01",
"desc": "package key must be or extend one of the pre-defined keys",
"tests": "be or starts with one of [bag, bale, barrel, bin, box, bundle, can, carton, case, crate, drum, envelope, pallet, reel, roll, sack, tray, tub, tube, unpacked]"
}
]
}
]
},
{
"field": "count",
"assert": [
{
"id": "GOBL-ORG-PACKAGE-02",
"desc": "package count must be zero or positive",
"tests": "at least 0"
}
]
},
{
"field": "attributes",
"assert": [
{
"id": "GOBL-ORG-PACKAGE-03",
"desc": "package attributes must not contain duplicate keys",
"tests": "attribute keys must be unique"
}
]
}
]
},
{
"id": "GOBL-ORG-PERSON",
"object": "org.Person",
Expand Down
8 changes: 8 additions & 0 deletions data/schemas/bill/line.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@
"title": "Breakdown",
"description": "Breakdown of the line item for more detailed information. The sum of all lines\nwill be used for the item price."
},
"packages": {
"items": {
"$ref": "https://gobl.org/draft-0/org/package"
},
"type": "array",
"title": "Packages",
"description": "Packages describe the physical packages or containers used to pack and\nship the line's items, most useful in delivery documents."
},
"sum": {
"$ref": "https://gobl.org/draft-0/num/amount",
"title": "Sum",
Expand Down
137 changes: 137 additions & 0 deletions data/schemas/org/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://gobl.org/draft-0/org/package",
"$ref": "#/$defs/org.Package",
"$defs": {
"org.Package": {
"properties": {
"uuid": {
"type": "string",
"format": "uuid",
"title": "UUID",
"description": "Universally Unique Identifier."
},
"label": {
"type": "string",
"title": "Label",
"description": "Label for the package for presentation in output documents."
},
"key": {
"$ref": "https://gobl.org/draft-0/cbc/key",
"anyOf": [
{
"const": "bag",
"title": "Bag"
},
{
"const": "bale",
"title": "Bale"
},
{
"const": "barrel",
"title": "Barrel"
},
{
"const": "bin",
"title": "Bin"
},
{
"const": "box",
"title": "Box"
},
{
"const": "bundle",
"title": "Bundle"
},
{
"const": "can",
"title": "Can"
},
{
"const": "carton",
"title": "Carton"
},
{
"const": "case",
"title": "Case"
},
{
"const": "crate",
"title": "Crate"
},
{
"const": "drum",
"title": "Drum"
},
{
"const": "envelope",
"title": "Envelope"
},
{
"const": "pallet",
"title": "Pallet"
},
{
"const": "reel",
"title": "Reel"
},
{
"const": "roll",
"title": "Roll"
},
{
"const": "sack",
"title": "Sack"
},
{
"const": "tray",
"title": "Tray"
},
{
"const": "tub",
"title": "Tub"
},
{
"const": "tube",
"title": "Tube"
},
{
"const": "unpacked",
"title": "Unpacked",
"description": "Unpacked or unpackaged goods."
},
{
"pattern": "^(?:[a-z]|[a-z0-9][a-z0-9-+]*[a-z0-9])$",
"title": "Other"
}
],
"title": "Key",
"description": "Key for the type of package, based on the list pre-defined by GOBL\nwith mappings to UN/ECE Recommendation 21 codes."
},
"count": {
"type": "integer",
"title": "Count",
"description": "Count of packages of this same type, when more than one."
},
"identities": {
"items": {
"$ref": "https://gobl.org/draft-0/org/identity"
},
"type": "array",
"title": "Identities",
"description": "Identities used to identify the individual package, such as a\nGS1 Serial Shipping Container Code (SSCC)."
},
"attributes": {
"items": {
"$ref": "https://gobl.org/draft-0/org/attribute"
},
"type": "array",
"title": "Attributes",
"description": "Attributes describe features of the package, such as its dimensions\nand gross weight."
}
},
"type": "object",
"description": "Package describes a physical package or container used to pack and ship an item, based on the UBL \"Package\" class."
}
}
}
7 changes: 7 additions & 0 deletions examples/es/delivery.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,10 @@ lines:
item:
name: "Promo Mugs"
price: "12.50"
packages:
- key: "box"
count: 2
attributes:
- key: "weight"
amount: "3.5"
unit: "kg"
15 changes: 14 additions & 1 deletion examples/es/out/delivery.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"uuid": "8a51fd30-2a27-11ee-be56-0242ac120002",
"dig": {
"alg": "sha256",
"val": "26e0d92f3290c44676c0de4df677e6710174a5a93a5ea6f843f956175d9cca42"
"val": "0be5694841e9dfc76f3dfada9e65f65a2fb5e9474c3976f42f960cb54e53c1b2"
}
},
"doc": {
Expand Down Expand Up @@ -56,6 +56,19 @@
"name": "Promo Mugs",
"price": "12.50"
},
"packages": [
{
"key": "box",
"count": 2,
"attributes": [
{
"key": "weight",
"amount": "3.5",
"unit": "kg"
}
]
}
],
"sum": "125.00",
"total": "125.00"
}
Expand Down
1 change: 1 addition & 0 deletions org/norm.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ func init() {
norm.For(normalizeWebsite),
norm.For(normalizeAttachment),
norm.For(normalizeAttribute),
norm.For(normalizePackage),
)
}
2 changes: 2 additions & 0 deletions org/org.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ func init() {
Item{},
Name{},
Note{},
Package{},
Party{},
Person{},
Registration{},
Expand All @@ -43,6 +44,7 @@ func init() {
itemRules(),
nameRules(),
noteRules(),
packageRules(),
personRules(),
registrationRules(),
telephoneRules(),
Expand Down
Loading
Loading