Skip to main content

A Python toolkit for logistics and supply chain calculations

Project description

logisticspy

A growing Python toolkit for logistics and supply chain calculations.

logisticspy gives developers clean, well-tested building blocks for common logistics problems — from freight weight calculations to warehouse inventory management. Each module is self-contained, production-ready, and designed to slot into existing systems without friction.

pip install logisticspy

📖 New to logisticspy? Start with the Beginner's User Guide (downloadable .docx), also attached to every GitHub release.


What's inside

Module What it does
logisticspy.weight Calculate chargeable weight & volumetric weight for air, courier, road, rail, and sea freight
logisticspy.packwise Convert between units of measure (UOM) and consolidate packaging hierarchies — pallets → cartons → each

More modules are planned: volume calculations, freight cost estimation, transit time tools, and more.


Quick start

Chargeable weight (air freight)

import logisticspy

result = logisticspy.calculate(
    length=60, width=40, height=40, unit="cm",
    actual_weight=18, weight_unit="kg",
    mode="air",
)

print(result.volumetric_weight_kg)   # 16.0
print(result.chargeable_weight_kg)   # 18.0  ← actual weight wins
print(result.basis)                  # "actual"

UOM conversion & stock tracking (warehouse)

from decimal import Decimal
from logisticspy.packwise import (
    discrete_standard, PALLET, EACH,
    ProductUOMConfig, GRNBehavior, StockLedger,
)

hierarchy = discrete_standard()   # PLT → CTN → BOX → EA  (10 / 12 / 6)

cfg = ProductUOMConfig(
    sku="OIL-500ML",
    hierarchy=hierarchy,
    purchase_uom=PALLET,
    sale_uom=EACH,
    grn_behavior=GRNBehavior.CONSOLIDATE_UP,
)

ledger = StockLedger()
ledger.register(cfg)

ledger.receive_grn("OIL-500ML", [(PALLET, Decimal("1"))], reference="GRN-001")
ledger.fulfil_sale("OIL-500ML", Decimal("100"), reference="SO-001")

print(ledger.stock_level("OIL-500ML").base_qty)     # 620
print(ledger.stock_level("OIL-500ML").breakdown())  # [(CTN, 8), (BOX, 7), (EA, 2)]

The weight module: chargeable & volumetric weight

Carriers bill shipments based on whichever is greater: the actual weight or the volumetric weight (calculated from package dimensions). This module handles that calculation cleanly, with support for multiple units, transport modes, named divisor presets, and multi-package consignments.

Supported modes and default divisors

Mode Default divisor (cm³/kg)
air 6000
courier 5000
road 3000
rail 3000
sea N/A — uses CBM × 1000

Note: These are sensible defaults based on common industry conventions. They are not tied to any specific carrier. Always confirm the applicable divisor with your carrier or contract for billing-critical calculations.

Divisor presets

Two divisor values — 5000 and 6000 — are both widely used, sometimes even by the same carrier depending on the service or region. Use named presets to switch between them easily:

Preset Divisor
"a" 5000
"b" 6000
import logisticspy

pkg = dict(length=60, width=40, height=40, actual_weight=10, mode="air")

result_a = logisticspy.calculate(**pkg, divisor_preset="a")  # divisor 5000
result_b = logisticspy.calculate(**pkg, divisor_preset="b")  # divisor 6000

print(result_a.volumetric_weight_kg)  # 19.2
print(result_b.volumetric_weight_kg)  # 16.0

# Or pass your carrier's exact divisor directly:
result = logisticspy.calculate(**pkg, divisor=4500)

Units

Input dimensions: cm, m, mm, in, ft (default: cm) Input weights: kg, g, lb, oz (default: kg)

result = logisticspy.calculate(
    length=20, width=15, height=10, unit="in",
    actual_weight=5, weight_unit="lb",
    mode="courier",
)

Output is always normalized:

Field Unit
actual_weight_kg, volumetric_weight_kg, chargeable_weight_kg kilograms (kg)
volume_m3 cubic metres (m³)

Sea freight (CBM)

result = logisticspy.calculate(
    length=1, width=1, height=1, unit="m",
    actual_weight=500, mode="sea",
)
print(result.volumetric_weight_kg)  # 1000.0  (1 CBM = 1000 kg equivalent)

Multi-package consignments

packages = [
    {"length": 50, "width": 40, "height": 40, "actual_weight": 10},
    {"length": 60, "width": 40, "height": 40, "actual_weight": 25, "quantity": 2},
]

result = logisticspy.calculate_consignment(packages, mode="air")

print(result.total_actual_weight_kg)
print(result.total_volumetric_weight_kg)
print(result.total_chargeable_weight_kg)

Use per_piece=True if your carrier calculates chargeable weight per package and then sums them:

result = logisticspy.calculate_consignment(packages, mode="air", per_piece=True)

The packwise module: UOM conversion & packaging consolidation

In warehouses and distribution centres, goods are often purchased in one unit of measure (pallets, drums, bulk bags) but sold in another (loose units, kilograms, packs). packwise bridges that gap.

It always stores stock internally in base units — the smallest unit in the hierarchy — so all conversions are computed from a single number with no rounding drift across levels.

Preset hierarchies

Five ready-to-use presets cover the most common industries. All conversion factors are overridable.

Preset Hierarchy Default factors Base unit
discrete_standard() PLT → CTN → BOX → EA 10 / 12 / 6 Each
dry_bulk() PLT → BAG → KG → G 40 / 25 / 1000 Gram (decimal)
liquid_bulk() PLT → DRUM → L → ML 4 / 200 / 1000 mL (decimal)
apparel() PLT → CTN → PACK → PC 20 / 10 / 5 Piece
pharma() PLT → SHIP → INNER → STRIP → TAB 20 / 12 / 10 / 10 Tablet

What's included

  • UOMHierarchy — model any parent→child packaging chain with conversion factors; convert between any two levels.
  • ProductUOMConfig / GRNBehavior — per-SKU purchase/sale UOMs and goods-receipt handling (NORMALIZE_TO_BASE, CONSOLIDATE_UP, KEEP_AS_IS, CUSTOM), with per-SKU factor overrides.
  • Stateless convertersconvert, consolidate_loose, process_grn_line, split_for_sale for one-off calculations without maintaining state.
  • StockLedger — stateful inventory tracking in base units with a full audit trail (GRN, sale, transfer, adjustment).
  • PackwisePlugin — hooks that turn logisticspy GRN / PO / SO / stock transfer documents into ledger movements.

Stock is tracked with decimal.Decimal throughout for exact arithmetic — no floating-point drift.


Roadmap

logisticspy is designed to grow into a comprehensive logistics toolkit. Current modules:

  • weight — chargeable & volumetric weight
  • packwise — UOM conversion & packaging consolidation

Planned:

  • 🔜 Volume and freight calculations
  • 🔜 Freight cost estimation helpers
  • 🔜 Transit time tools

Documentation

Disclaimer

This library implements widely-used industry conventions for illustrative and estimation purposes. Divisors and CBM ratios vary by carrier, service level, region, and contract terms. Always confirm exact billing methodology with your carrier or freight forwarder for invoicing-critical calculations.

Contributing

Contributions, bug reports, and feature requests are welcome. See CONTRIBUTING.md for guidelines.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

logisticspy-0.3.1.tar.gz (32.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

logisticspy-0.3.1-py3-none-any.whl (30.8 kB view details)

Uploaded Python 3

File details

Details for the file logisticspy-0.3.1.tar.gz.

File metadata

  • Download URL: logisticspy-0.3.1.tar.gz
  • Upload date:
  • Size: 32.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for logisticspy-0.3.1.tar.gz
Algorithm Hash digest
SHA256 a04327a7caeb6bebca6bf1d744086976c1c37206cb3aed175dac950b7d51b470
MD5 3b9ac746a9adf19199b1750de12528a0
BLAKE2b-256 35288d6b0868e55eeed0e95795bb136dfcc15a883cadb8ef2523da9ac6cfc512

See more details on using hashes here.

Provenance

The following attestation bundles were made for logisticspy-0.3.1.tar.gz:

Publisher: publish.yml on krishnanz550i-cmyk/logisticspy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file logisticspy-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: logisticspy-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 30.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for logisticspy-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b1dec3a057025f451b5b963611ac1da7db7ab964a93f911c3faa8bb839983300
MD5 16915dd99f57372ddc4058ce1552a0a7
BLAKE2b-256 8c11451a18e1d0cfc80a2111a52d3e1ad1d278bd5e5b59712e92c6a90fbf4702

See more details on using hashes here.

Provenance

The following attestation bundles were made for logisticspy-0.3.1-py3-none-any.whl:

Publisher: publish.yml on krishnanz550i-cmyk/logisticspy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page