diff --git a/brewman/alembic/versions/82e5c8d18382_mozimo_product_ledger.py b/brewman/alembic/versions/82e5c8d18382_mozimo_product_ledger.py
new file mode 100644
index 00000000..d9109e1a
--- /dev/null
+++ b/brewman/alembic/versions/82e5c8d18382_mozimo_product_ledger.py
@@ -0,0 +1,46 @@
+"""mozimo product ledger
+
+Revision ID: 82e5c8d18382
+Revises: fab52fb911e4
+Create Date: 2024-08-16 06:57:58.336202
+
+"""
+
+import sqlalchemy as sa
+
+from alembic import op
+
+
+# revision identifiers, used by Alembic.
+revision = "82e5c8d18382"
+down_revision = "fab52fb911e4"
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.create_table(
+        "mozimo_stock_register",
+        sa.Column("id", sa.Uuid(), nullable=False),
+        sa.Column("date", sa.Date(), nullable=False),
+        sa.Column("sku_id", sa.Uuid(), nullable=False),
+        sa.Column("received", sa.Numeric(precision=15, scale=2), nullable=False),
+        sa.Column("sale", sa.Numeric(precision=15, scale=2), nullable=False),
+        sa.Column("nc", sa.Numeric(precision=15, scale=2), nullable=False),
+        sa.Column("display", sa.Numeric(precision=15, scale=2), nullable=True),
+        sa.Column("ageing", sa.Numeric(precision=15, scale=2), nullable=True),
+        sa.Column("last_edit_date", sa.DateTime(), nullable=False),
+        sa.ForeignKeyConstraint(
+            ["sku_id"], ["stock_keeping_units.id"], name=op.f("fk_mozimo_stock_register_sku_id_stock_keeping_units")
+        ),
+        sa.PrimaryKeyConstraint("id", name=op.f("pk_mozimo_stock_register")),
+        sa.UniqueConstraint("date", "sku_id", name=op.f("uq_mozimo_stock_register_date")),
+    )
+    # ### end Alembic commands ###
+
+
+def downgrade():
+    # ### commands auto generated by Alembic - please adjust! ###
+    op.drop_table("mozimo_stock_register")
+    # ### end Alembic commands ###
diff --git a/brewman/brewman/db/base.py b/brewman/brewman/db/base.py
index 79020d24..96011167 100644
--- a/brewman/brewman/db/base.py
+++ b/brewman/brewman/db/base.py
@@ -17,6 +17,7 @@ from ..models.incentive import Incentive  # noqa: F401
 from ..models.inventory import Inventory  # noqa: F401
 from ..models.journal import Journal  # noqa: F401
 from ..models.login_history import LoginHistory  # noqa: F401
+from ..models.mozimo_stock_register import MozimoStockRegister  # noqa: F401
 from ..models.period import Period  # noqa: F401
 from ..models.permission import Permission  # noqa: F401
 from ..models.price import Price  # noqa: F401
diff --git a/brewman/brewman/main.py b/brewman/brewman/main.py
index 99f36cd5..ff216e0b 100644
--- a/brewman/brewman/main.py
+++ b/brewman/brewman/main.py
@@ -53,6 +53,7 @@ from .routers.reports import (
     daybook,
     entries,
     ledger,
+    mozimo_product_register,
     net_transactions,
     non_contract_purchase,
     product_ledger,
@@ -114,6 +115,8 @@ app.include_router(trial_balance.router, prefix="/api/trial-balance", tags=["rep
 app.include_router(entries.router, prefix="/api/entries", tags=["reports"])
 app.include_router(batch_integrity.router, prefix="/api/batch-integrity", tags=["reports"])
 app.include_router(non_contract_purchase.router, prefix="/api/non-contract-purchase", tags=["reports"])
+app.include_router(mozimo_product_register.router, prefix="/api/mozimo-product-register", tags=["mozimo"])
+
 
 app.include_router(issue_grid.router, prefix="/api/issue-grid", tags=["vouchers"])
 app.include_router(batch.router, prefix="/api/batch", tags=["vouchers"])
diff --git a/brewman/brewman/models/mozimo_stock_register.py b/brewman/brewman/models/mozimo_stock_register.py
new file mode 100644
index 00000000..8a459a95
--- /dev/null
+++ b/brewman/brewman/models/mozimo_stock_register.py
@@ -0,0 +1,63 @@
+from __future__ import annotations
+
+import uuid
+
+from datetime import UTC, date, datetime
+from decimal import Decimal
+from typing import TYPE_CHECKING
+
+from sqlalchemy import Date, DateTime, ForeignKey, Numeric, UniqueConstraint, Uuid
+from sqlalchemy.orm import Mapped, mapped_column, relationship
+
+from ..db.base_class import reg
+
+
+if TYPE_CHECKING:
+    from .stock_keeping_unit import StockKeepingUnit
+
+
+@reg.mapped_as_dataclass(unsafe_hash=True)
+class MozimoStockRegister:
+    __tablename__ = "mozimo_stock_register"
+    __table_args__ = (UniqueConstraint("date", "sku_id"),)
+    id_: Mapped[uuid.UUID] = mapped_column("id", Uuid, primary_key=True, insert_default=uuid.uuid4)
+    date_: Mapped[date] = mapped_column("date", Date, nullable=False)
+    sku_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("stock_keeping_units.id"), nullable=False)
+    received: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=False)
+    sale: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=False)
+    nc: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=False)
+    # The physical stock in the display area
+    display: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=True)
+    # The physical stock in the ageing room
+    ageing: Mapped[Decimal] = mapped_column(Numeric(precision=15, scale=2), nullable=True)
+    last_edit_date: Mapped[datetime] = mapped_column(DateTime(), nullable=False)
+
+    sku: Mapped[StockKeepingUnit] = relationship("StockKeepingUnit")
+
+    def __init__(
+        self,
+        date_: datetime.date,
+        received: Decimal,
+        sale: Decimal,
+        nc: Decimal,
+        display: Decimal,
+        ageing: Decimal,
+        sku_id: uuid.UUID | None = None,
+        sku: StockKeepingUnit | None = None,
+        id_: uuid.UUID | None = None,
+        last_edit_date: datetime | None = None,
+    ):
+        self.date_ = date_
+        self.received = received
+        self.sale = sale
+        self.nc = nc
+        self.display = display
+        self.ageing = ageing
+        if sku_id is not None:
+            self.sku_id = sku_id
+        if sku is not None:
+            self.sku = sku
+            self.sku_id = sku.id
+        if id_ is not None:
+            self.id_ = id_
+        self.last_edit_date = last_edit_date or datetime.now(UTC).replace(tzinfo=None)
diff --git a/brewman/brewman/routers/reports/mozimo_product_register.py b/brewman/brewman/routers/reports/mozimo_product_register.py
new file mode 100644
index 00000000..2b4bf797
--- /dev/null
+++ b/brewman/brewman/routers/reports/mozimo_product_register.py
@@ -0,0 +1,203 @@
+import uuid
+
+from datetime import UTC, date, datetime
+from decimal import Decimal
+
+from fastapi import APIRouter, HTTPException, Request, Security, status
+from sqlalchemy import desc
+from sqlalchemy.exc import SQLAlchemyError
+from sqlalchemy.orm import Session
+from sqlalchemy.sql.expression import select
+
+import brewman.schemas.mozimo_product_register as schemas
+
+from ...core.security import get_current_active_user as get_user
+from ...core.session import get_finish_date, get_start_date, set_period
+from ...db.session import SessionFuture
+from ...models.mozimo_stock_register import MozimoStockRegister
+from ...models.stock_keeping_unit import StockKeepingUnit
+from ...schemas.user import UserToken
+from ..attendance import date_range
+
+
+router = APIRouter()
+
+
+@router.get("", response_model=schemas.MozimoProductRegister)
+def show_blank(
+    request: Request,
+    user: UserToken = Security(get_user, scopes=["ledger"]),
+) -> schemas.MozimoProductRegister:
+    return schemas.MozimoProductRegister(
+        start_date=get_start_date(request.session),
+        finish_date=get_finish_date(request.session),
+        product=None,
+        body=[],
+    )
+
+
+@router.get("/{id_}", response_model=schemas.MozimoProductRegister)
+def show_data(
+    id_: uuid.UUID,
+    request: Request,
+    s: str | None = None,
+    f: str | None = None,
+    user: UserToken = Security(get_user, scopes=["ledger"]),
+) -> schemas.MozimoProductRegister:
+    with SessionFuture() as db:
+        sku = db.execute(select(StockKeepingUnit).where(StockKeepingUnit.id == id_)).scalar_one()
+        start_date = datetime.strptime(s or get_start_date(request.session), "%d-%b-%Y").date()
+        finish_date = datetime.strptime(f or get_finish_date(request.session), "%d-%b-%Y").date()
+        body = build_report(sku.id, start_date, finish_date, db)
+        set_period(start_date, finish_date, request.session)
+        return schemas.MozimoProductRegister(
+            start_date=start_date,
+            finish_date=finish_date,
+            product=schemas.ProductLink(id_=sku.id, name=f"{sku.product.name} ({sku.units})"),
+            body=body,
+        )
+
+
+def build_report(
+    product_id: uuid.UUID, start_date: date, finish_date: date, db: Session
+) -> list[schemas.MozimoProductRegisterItem]:
+    body = []
+    ob = opening_balance(product_id, start_date, db)
+
+    for date_ in date_range(start_date, finish_date, inclusive=True):
+        item = (
+            db.execute(
+                select(MozimoStockRegister).where(
+                    MozimoStockRegister.sku_id == product_id,
+                    MozimoStockRegister.date_ == date_,
+                )
+            )
+            .scalars()
+            .one_or_none()
+        )
+
+        body.append(
+            schemas.MozimoProductRegisterItem(
+                id_=None if item is None else item.id_,
+                date_=date_,
+                opening=ob,
+                received=Decimal(0) if item is None else item.received,
+                sale=Decimal(0) if item is None else item.sale,
+                nc=Decimal(0) if item is None else item.nc,
+                display=None if item is None else item.display,
+                ageing=None if item is None else item.ageing,
+                last_edit_date=None if item is None else item.last_edit_date,
+            )
+        )
+        if item is not None:
+            if item.ageing is not None or item.display is not None:
+                closing = (item.ageing or 0) + (item.display or 0)
+            else:
+                closing = ob + item.received - item.sale - item.nc
+            ob = closing  # Setting the cb as ob for next iteration
+    return body
+
+
+def opening_balance(product_id: uuid.UUID, start_date: date, db: Session) -> Decimal:
+    opening = db.execute(
+        select(MozimoStockRegister.display + MozimoStockRegister.ageing)
+        .order_by(desc(MozimoStockRegister.date_))
+        .where(
+            MozimoStockRegister.sku_id == product_id,
+            MozimoStockRegister.date_ < start_date,
+        )
+    ).scalar()
+    return Decimal(0) if opening is None else opening
+
+
+@router.post("", response_model=schemas.MozimoProductRegister)
+def save_route(
+    request: Request,
+    data: schemas.MozimoProductRegister,
+    user: UserToken = Security(get_user, scopes=["ledger"]),
+) -> schemas.MozimoProductRegister:
+    try:
+        if any(i for i in data.body if i.received < 0):
+            raise HTTPException(
+                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+                detail="Received cannot be less than 0.",
+            )
+        if any(i for i in data.body if i.sale < 0):
+            raise HTTPException(
+                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+                detail="Sale cannot be less than 0.",
+            )
+        if any(i for i in data.body if i.nc < 0):
+            raise HTTPException(
+                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+                detail="No Charge cannot be less than 0.",
+            )
+        if any(i for i in data.body if i.display is not None and i.display < 0):
+            raise HTTPException(
+                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+                detail="Quantity on display can be Blank, but cannot be less than 0.",
+            )
+        if any(i for i in data.body if i.ageing is not None and i.ageing < 0):
+            raise HTTPException(
+                status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+                detail="Quantity in ageing room can be Blank, but cannot be less than 0.",
+            )
+        with SessionFuture() as db:
+            now = datetime.now(UTC).replace(tzinfo=None)
+            ob = opening_balance(data.product.id_, data.start_date, db)
+            for item in data.body:
+                if item.ageing is not None or item.display is not None:
+                    closing = (item.ageing or 0) + (item.display or 0)
+                else:
+                    closing = ob + item.received - item.sale - item.nc
+                ob = closing  # Setting the cb as ob for next iteration
+                if closing < 0:
+                    raise HTTPException(
+                        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
+                        detail="Closing Stock cannot be less than 0.",
+                    )
+
+            for item in data.body:
+                old = (
+                    db.execute(
+                        select(MozimoStockRegister).where(
+                            MozimoStockRegister.sku_id == data.product.id_,
+                            MozimoStockRegister.date_ == item.date_,
+                        )
+                    )
+                    .scalars()
+                    .one_or_none()
+                )
+                if old is not None:
+                    if (
+                        old.received != item.received
+                        or old.sale != item.sale
+                        or old.nc != item.nc
+                        or old.display != item.display
+                        or old.ageing != item.ageing
+                    ):
+                        old.received = item.received
+                        old.sale = item.sale
+                        old.nc = item.nc
+                        old.display = item.display
+                        old.ageing = item.ageing
+                        old.last_edit_date = now
+                else:
+                    entry = MozimoStockRegister(
+                        item.date_, item.received, item.sale, item.nc, item.display, item.ageing, data.product.id_
+                    )
+                    db.add(entry)
+
+            body = build_report(data.product.id_, data.start_date, data.finish_date, db)
+            db.commit()
+            return schemas.MozimoProductRegister(
+                start_date=data.start_date,
+                finish_date=data.finish_date,
+                product=data.product,
+                body=body,
+            )
+    except SQLAlchemyError as e:
+        raise HTTPException(
+            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
+            detail=str(e),
+        )
diff --git a/brewman/brewman/schemas/mozimo_product_register.py b/brewman/brewman/schemas/mozimo_product_register.py
new file mode 100644
index 00000000..f8c276f9
--- /dev/null
+++ b/brewman/brewman/schemas/mozimo_product_register.py
@@ -0,0 +1,85 @@
+import uuid
+
+from datetime import date, datetime
+
+from pydantic import (
+    BaseModel,
+    ConfigDict,
+    FieldSerializationInfo,
+    field_serializer,
+    field_validator,
+)
+
+from . import Daf, to_camel
+from .product import ProductLink
+
+
+class MozimoProductRegisterItem(BaseModel):
+    id_: uuid.UUID | None = None
+    date_: date
+    opening: Daf
+    received: Daf
+    sale: Daf
+    nc: Daf
+    display: Daf | None
+    ageing: Daf | None
+    last_edit_date: datetime | None = None
+    model_config = ConfigDict(str_strip_whitespace=True, alias_generator=to_camel, populate_by_name=True)
+
+    @field_validator("date_", mode="before")
+    @classmethod
+    def parse_date(cls, value: date | str) -> date:
+        if isinstance(value, date):
+            return value
+        return datetime.strptime(value, "%d-%b-%Y").date()
+
+    @field_serializer("date_")
+    def serialize_date(self, value: date, info: FieldSerializationInfo) -> str:
+        return value.strftime("%d-%b-%Y")
+
+    @field_validator("last_edit_date", mode="before")
+    @classmethod
+    def parse_last_edit_date(cls, value: None | datetime | str) -> datetime | None:
+        if value is None or value == "":
+            return None
+        if isinstance(value, datetime):
+            return value
+        return datetime.strptime(value, "%d-%b-%Y %H:%M")
+
+    @field_serializer("last_edit_date")
+    def serialize_last_edit_date(self, value: datetime, info: FieldSerializationInfo) -> str | None:
+        return None if value is None else value.strftime("%d-%b-%Y %H:%M")
+
+
+class MozimoProductRegister(BaseModel):
+    start_date: date | None = None
+    finish_date: date | None = None
+    product: ProductLink | None = None
+    body: list[MozimoProductRegisterItem]
+    model_config = ConfigDict(str_strip_whitespace=True, alias_generator=to_camel, populate_by_name=True)
+
+    @field_validator("start_date", mode="before")
+    @classmethod
+    def parse_start_date(cls, value: date | str | None) -> date | None:
+        if value is None:
+            return None
+        if isinstance(value, date):
+            return value
+        return datetime.strptime(value, "%d-%b-%Y").date()
+
+    @field_serializer("start_date")
+    def serialize_start_date(self, value: date, info: FieldSerializationInfo) -> str | None:
+        return None if value is None else value.strftime("%d-%b-%Y")
+
+    @field_validator("finish_date", mode="before")
+    @classmethod
+    def parse_finish_date(cls, value: date | str | None) -> date | None:
+        if value is None:
+            return None
+        if isinstance(value, date):
+            return value
+        return datetime.strptime(value, "%d-%b-%Y").date()
+
+    @field_serializer("finish_date")
+    def serialize_finish_date(self, value: date, info: FieldSerializationInfo) -> str | None:
+        return None if value is None else value.strftime("%d-%b-%Y")
diff --git a/overlord/src/app/app.routes.ts b/overlord/src/app/app.routes.ts
index 67e2e0f9..e38904bd 100644
--- a/overlord/src/app/app.routes.ts
+++ b/overlord/src/app/app.routes.ts
@@ -89,6 +89,10 @@ export const routes: Routes = [
     path: 'ledger',
     loadChildren: () => import('./ledger/ledger.routes').then((mod) => mod.routes),
   },
+  {
+    path: 'mozimo-product-register',
+    loadChildren: () => import('./mozimo-product-register/mozimo-product-register.routes').then((mod) => mod.routes),
+  },
   {
     path: 'net-transactions',
     loadChildren: () => import('./net-transactions/net-transactions.routes').then((mod) => mod.routes),
diff --git a/overlord/src/app/core/nav-bar/nav-bar.component.html b/overlord/src/app/core/nav-bar/nav-bar.component.html
index fb5969e1..66510dcb 100644
--- a/overlord/src/app/core/nav-bar/nav-bar.component.html
+++ b/overlord/src/app/core/nav-bar/nav-bar.component.html
@@ -35,6 +35,7 @@
     <a mat-menu-item routerLink="/rate-contracts">Rate Contracts</a>
     <a mat-menu-item routerLink="/batch-integrity-report">Batch Integrity</a>
     <a mat-menu-item routerLink="/non-contract-purchase">Non Contract Purchases</a>
+    <a mat-menu-item routerLink="/mozimo-product-register">Mozimo Product Register</a>
   </mat-menu>
   <button mat-button [matMenuTriggerFor]="productReportMenu">Product Reports</button>
 
diff --git a/overlord/src/app/mozimo-product-register/mozimo-product-register-datasource.ts b/overlord/src/app/mozimo-product-register/mozimo-product-register-datasource.ts
new file mode 100644
index 00000000..645bc494
--- /dev/null
+++ b/overlord/src/app/mozimo-product-register/mozimo-product-register-datasource.ts
@@ -0,0 +1,66 @@
+import { DataSource } from '@angular/cdk/collections';
+import { EventEmitter } from '@angular/core';
+import { MatPaginator, PageEvent } from '@angular/material/paginator';
+import { merge, Observable } from 'rxjs';
+import { map, tap } from 'rxjs/operators';
+
+import { MozimoProductRegisterItem } from './mozimo-product-register-item';
+
+export class MozimoProductRegisterDataSource extends DataSource<MozimoProductRegisterItem> {
+  public data: MozimoProductRegisterItem[] = [];
+  public paginator?: MatPaginator;
+  constructor(public dataObs: Observable<MozimoProductRegisterItem[]>) {
+    super();
+  }
+
+  connect(): Observable<MozimoProductRegisterItem[]> {
+    const dataMutations: EventEmitter<PageEvent>[] = [];
+    const d = this.dataObs.pipe(
+      tap((x) => {
+        this.data = x;
+      }),
+    );
+    if (this.paginator) {
+      dataMutations.push((this.paginator as MatPaginator).page);
+    }
+
+    return merge(d, ...dataMutations).pipe(
+      map(() => this.calculate([...this.data])),
+      tap(() => {
+        if (this.paginator) {
+          this.paginator.length = this.data.length;
+        }
+      }),
+      map((x: MozimoProductRegisterItem[]) => this.getPagedData(x)),
+    );
+  }
+
+  disconnect() {}
+
+  private calculate(data: MozimoProductRegisterItem[]): MozimoProductRegisterItem[] {
+    if (data.length === 0) {
+      return data;
+    }
+    let ob = data[0].opening;
+    data.forEach((item) => {
+      item.opening = ob;
+      if (item.ageing !== null || item.display !== null) {
+        item.closing = (item.ageing ?? 0) + (item.display ?? 0);
+        item.variance = item.opening + item.received - item.sale - item.nc - item.closing;
+      } else {
+        item.closing = item.opening + item.received - item.sale - item.nc;
+        item.variance = 0;
+      }
+      ob = item.closing;
+    });
+    return data;
+  }
+
+  private getPagedData(data: MozimoProductRegisterItem[]) {
+    if (this.paginator === undefined) {
+      return data;
+    }
+    const startIndex = this.paginator.pageIndex * this.paginator.pageSize;
+    return data.splice(startIndex, this.paginator.pageSize);
+  }
+}
diff --git a/overlord/src/app/mozimo-product-register/mozimo-product-register-item.ts b/overlord/src/app/mozimo-product-register/mozimo-product-register-item.ts
new file mode 100644
index 00000000..9fc0468e
--- /dev/null
+++ b/overlord/src/app/mozimo-product-register/mozimo-product-register-item.ts
@@ -0,0 +1,28 @@
+export class MozimoProductRegisterItem {
+  id: string | null;
+  date: string;
+  opening: number;
+  received: number;
+  sale: number;
+  nc: number;
+  display: number | null;
+  ageing: number | null;
+  variance: number | null;
+  closing: number;
+  lastEditDate: string | null;
+
+  public constructor(init?: Partial<MozimoProductRegisterItem>) {
+    this.id = null;
+    this.date = '';
+    this.opening = 0;
+    this.received = 0;
+    this.sale = 0;
+    this.nc = 0;
+    this.display = null;
+    this.ageing = null;
+    this.variance = null;
+    this.closing = 0;
+    this.lastEditDate = null;
+    Object.assign(this, init);
+  }
+}
diff --git a/overlord/src/app/mozimo-product-register/mozimo-product-register.component.css b/overlord/src/app/mozimo-product-register/mozimo-product-register.component.css
new file mode 100644
index 00000000..bfd7f853
--- /dev/null
+++ b/overlord/src/app/mozimo-product-register/mozimo-product-register.component.css
@@ -0,0 +1,17 @@
+.right {
+  display: flex;
+  justify-content: flex-end;
+}
+
+.first {
+  margin-right: 4px;
+}
+
+.middle {
+  margin-left: 4px;
+  margin-right: 4px;
+}
+
+.last {
+  margin-left: 4px;
+}
diff --git a/overlord/src/app/mozimo-product-register/mozimo-product-register.component.html b/overlord/src/app/mozimo-product-register/mozimo-product-register.component.html
new file mode 100644
index 00000000..0fe89837
--- /dev/null
+++ b/overlord/src/app/mozimo-product-register/mozimo-product-register.component.html
@@ -0,0 +1,164 @@
+<mat-card>
+  <mat-card-header>
+    <mat-card-title-group>
+      <mat-card-title>Mozimo Product Register</mat-card-title>
+      @if (dataSource.data.length) {
+        <button mat-icon-button (click)="exportCsv()">
+          <mat-icon>save_alt</mat-icon>
+        </button>
+      }
+    </mat-card-title-group>
+  </mat-card-header>
+  <mat-card-content>
+    <form [formGroup]="form" class="flex flex-col">
+      <div class="flex flex-row justify-around content-start items-start sm:max-lg:flex-col">
+        <mat-form-field class="flex-auto mr-5">
+          <mat-label>Start Date</mat-label>
+          <input
+            matInput
+            #startDateElement
+            [matDatepicker]="startDate"
+            formControlName="startDate"
+            autocomplete="off"
+          />
+          <mat-datepicker-toggle matSuffix [for]="startDate"></mat-datepicker-toggle>
+          <mat-datepicker #startDate></mat-datepicker>
+        </mat-form-field>
+        <mat-form-field class="flex-auto">
+          <mat-label>Finish Date</mat-label>
+          <input matInput [matDatepicker]="finishDate" formControlName="finishDate" autocomplete="off" />
+          <mat-datepicker-toggle matSuffix [for]="finishDate"></mat-datepicker-toggle>
+          <mat-datepicker #finishDate></mat-datepicker>
+        </mat-form-field>
+      </div>
+      <div class="flex flex-row justify-around content-start items-start sm:max-lg:flex-col">
+        <mat-form-field class="flex-auto basis-4/5 mr-5">
+          <mat-label>Product</mat-label>
+          <input
+            type="text"
+            matInput
+            #productElement
+            [matAutocomplete]="auto"
+            formControlName="product"
+            autocomplete="off"
+          />
+          <mat-autocomplete
+            #auto="matAutocomplete"
+            autoActiveFirstOption
+            [displayWith]="displayFn"
+            (optionSelected)="selected($event)"
+          >
+            @for (product of products | async; track product) {
+              <mat-option [value]="product">{{ product.name }}</mat-option>
+            }
+          </mat-autocomplete>
+        </mat-form-field>
+        <button mat-raised-button class="flex-auto basis-1/5" color="primary" (click)="show()">Show</button>
+      </div>
+      <mat-table #table [dataSource]="dataSource" aria-label="Elements" formArrayName="items">
+        <!-- Date Column -->
+        <ng-container matColumnDef="date">
+          <mat-header-cell *matHeaderCellDef class="center first">Date</mat-header-cell>
+          <mat-cell *matCellDef="let row" class="center first">
+            <span
+              matBadge="1"
+              matBadgeSize="small"
+              [matBadgeHidden]="!row.lastEditDate"
+              matTooltip="{{ row.lastEditDate | localTime }}"
+              [matTooltipDisabled]="!row.lastEditDate"
+              >{{ row.date }}</span
+            >
+          </mat-cell>
+        </ng-container>
+
+        <!-- Opening Column -->
+        <ng-container matColumnDef="opening">
+          <mat-header-cell *matHeaderCellDef class="right middle">Opening</mat-header-cell>
+          <mat-cell *matCellDef="let row" class="right middle">{{ row.opening | number: '0.2-2' }}</mat-cell>
+        </ng-container>
+
+        <!-- Received Column -->
+        <ng-container matColumnDef="received">
+          <mat-header-cell *matHeaderCellDef class="middle">Received</mat-header-cell>
+          <mat-cell *matCellDef="let row; let i = index" [formGroupName]="i" class="middle">
+            <mat-form-field class="flex-auto">
+              <mat-label>Received</mat-label>
+              <input matInput type="number" formControlName="received" (change)="updateReceived($event, row)" />
+            </mat-form-field>
+          </mat-cell>
+        </ng-container>
+
+        <!-- Sale Column -->
+        <ng-container matColumnDef="sale">
+          <mat-header-cell *matHeaderCellDef class="middle">Sale</mat-header-cell>
+          <mat-cell *matCellDef="let row; let i = index" [formGroupName]="i" class="middle">
+            <mat-form-field class="flex-auto">
+              <mat-label>Sale</mat-label>
+              <input matInput type="number" formControlName="sale" (change)="updateSale($event, row)" />
+            </mat-form-field>
+          </mat-cell>
+        </ng-container>
+
+        <!-- Nc Column -->
+        <ng-container matColumnDef="nc">
+          <mat-header-cell *matHeaderCellDef class="middle">Nc</mat-header-cell>
+          <mat-cell *matCellDef="let row; let i = index" [formGroupName]="i" class="middle">
+            <mat-form-field class="flex-auto">
+              <mat-label>Nc</mat-label>
+              <input matInput type="number" formControlName="nc" (change)="updateNc($event, row)" />
+            </mat-form-field>
+          </mat-cell>
+        </ng-container>
+
+        <!-- Display Column -->
+        <ng-container matColumnDef="display">
+          <mat-header-cell *matHeaderCellDef class="middle">Display</mat-header-cell>
+          <mat-cell *matCellDef="let row; let i = index" [formGroupName]="i" class="middle">
+            <mat-form-field class="flex-auto">
+              <mat-label>Display</mat-label>
+              <input matInput type="number" formControlName="display" (change)="updateDisplay($event, row)" />
+            </mat-form-field>
+          </mat-cell>
+        </ng-container>
+
+        <!-- Ageing Column -->
+        <ng-container matColumnDef="ageing">
+          <mat-header-cell *matHeaderCellDef class="middle">Ageing</mat-header-cell>
+          <mat-cell *matCellDef="let row; let i = index" [formGroupName]="i" class="middle">
+            <mat-form-field class="flex-auto">
+              <mat-label>Ageing</mat-label>
+              <input matInput type="number" formControlName="ageing" (change)="updateAgeing($event, row)" />
+            </mat-form-field>
+          </mat-cell>
+        </ng-container>
+
+        <!-- Variance Column -->
+        <ng-container matColumnDef="variance">
+          <mat-header-cell *matHeaderCellDef class="right middle">Variance</mat-header-cell>
+          <mat-cell *matCellDef="let row" class="right middle">{{ row.variance | number: '0.2-2' }}</mat-cell>
+        </ng-container>
+
+        <!-- Closing Column -->
+        <ng-container matColumnDef="closing">
+          <mat-header-cell *matHeaderCellDef class="right last">Closing</mat-header-cell>
+          <mat-cell *matCellDef="let row" class="right last">{{ row.closing | number: '0.2-2' }}</mat-cell>
+        </ng-container>
+
+        <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
+        <mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
+      </mat-table>
+
+      <mat-paginator
+        #paginator
+        [length]="dataSource.data.length"
+        [pageIndex]="0"
+        [pageSize]="50"
+        [pageSizeOptions]="[25, 50, 100, 250, 300, 5000]"
+      >
+      </mat-paginator>
+    </form>
+  </mat-card-content>
+  <mat-card-actions>
+    <button mat-raised-button color="primary" (click)="save()" [disabled]="form.pristine">Save</button>
+  </mat-card-actions>
+</mat-card>
diff --git a/overlord/src/app/mozimo-product-register/mozimo-product-register.component.spec.ts b/overlord/src/app/mozimo-product-register/mozimo-product-register.component.spec.ts
new file mode 100644
index 00000000..c2ff9e68
--- /dev/null
+++ b/overlord/src/app/mozimo-product-register/mozimo-product-register.component.spec.ts
@@ -0,0 +1,22 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MozimoProductRegisterComponent } from './mozimo-product-register.component';
+
+describe('MozimoProductRegisterComponent', () => {
+  let component: MozimoProductRegisterComponent;
+  let fixture: ComponentFixture<MozimoProductRegisterComponent>;
+
+  beforeEach(async () => {
+    await TestBed.configureTestingModule({
+      imports: [MozimoProductRegisterComponent],
+    }).compileComponents();
+
+    fixture = TestBed.createComponent(MozimoProductRegisterComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/overlord/src/app/mozimo-product-register/mozimo-product-register.component.ts b/overlord/src/app/mozimo-product-register/mozimo-product-register.component.ts
new file mode 100644
index 00000000..266cdadc
--- /dev/null
+++ b/overlord/src/app/mozimo-product-register/mozimo-product-register.component.ts
@@ -0,0 +1,250 @@
+import { DecimalPipe, CurrencyPipe, AsyncPipe } from '@angular/common';
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { FormGroup, FormArray, FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatDatepickerModule } from '@angular/material/datepicker';
+import { MatDialog } from '@angular/material/dialog';
+import { MatBadgeModule } from '@angular/material/badge';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatIconModule } from '@angular/material/icon';
+import { MatInputModule } from '@angular/material/input';
+import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
+import { MatTableModule } from '@angular/material/table';
+import { ActivatedRoute, Router } from '@angular/router';
+import moment from 'moment';
+
+import { AuthService } from '../auth/auth.service';
+import { MatSnackBar } from '@angular/material/snack-bar';
+import { ToCsvService } from '../shared/to-csv.service';
+
+import { MozimoProductRegister } from './mozimo-product-register';
+import { MozimoProductRegisterDataSource } from './mozimo-product-register-datasource';
+import { MozimoProductRegisterItem } from './mozimo-product-register-item';
+import { MozimoProductRegisterService } from './mozimo-product-register.service';
+import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
+import { Product } from '../core/product';
+import { debounceTime, distinctUntilChanged, Observable, switchMap, of as observableOf, BehaviorSubject } from 'rxjs';
+import { ProductSku } from '../core/product-sku';
+import { ProductService } from '../product/product.service';
+import { LocalTimePipe } from '../shared/local-time.pipe';
+import { MatTooltipModule } from '@angular/material/tooltip';
+
+@Component({
+  selector: 'app-mozimo-product-register',
+  templateUrl: './mozimo-product-register.component.html',
+  styleUrls: ['./mozimo-product-register.component.css'],
+  standalone: true,
+  imports: [
+    AsyncPipe,
+    CurrencyPipe,
+    DecimalPipe,
+    LocalTimePipe,
+    MatAutocompleteModule,
+    MatBadgeModule,
+    MatButtonModule,
+    MatCardModule,
+    MatDatepickerModule,
+    MatFormFieldModule,
+    MatIconModule,
+    MatInputModule,
+    MatPaginatorModule,
+    MatTableModule,
+    MatTooltipModule,
+    ReactiveFormsModule,
+  ],
+})
+export class MozimoProductRegisterComponent implements OnInit {
+  @ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
+  info: MozimoProductRegister = new MozimoProductRegister();
+  body = new BehaviorSubject<MozimoProductRegisterItem[]>([]);
+  dataSource: MozimoProductRegisterDataSource = new MozimoProductRegisterDataSource(this.body);
+
+  form: FormGroup<{
+    startDate: FormControl<Date>;
+    finishDate: FormControl<Date>;
+    product: FormControl<string | null>;
+    items: FormArray<
+      FormGroup<{
+        received: FormControl<number>;
+        sale: FormControl<number>;
+        nc: FormControl<number>;
+        display: FormControl<number | null>;
+        ageing: FormControl<number | null>;
+      }>
+    >;
+  }>;
+  /** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
+
+  displayedColumns = ['date', 'opening', 'received', 'sale', 'nc', 'display', 'ageing', 'variance', 'closing'];
+
+  products: Observable<ProductSku[]>;
+
+  constructor(
+    private route: ActivatedRoute,
+    private router: Router,
+    private toCsv: ToCsvService,
+    private dialog: MatDialog,
+    private snackBar: MatSnackBar,
+    public auth: AuthService,
+    private ser: MozimoProductRegisterService,
+    private productSer: ProductService,
+  ) {
+    this.form = new FormGroup({
+      startDate: new FormControl(new Date(), { nonNullable: true }),
+      finishDate: new FormControl(new Date(), { nonNullable: true }),
+      product: new FormControl<string | null>(null),
+      items: new FormArray<
+        FormGroup<{
+          received: FormControl<number>;
+          sale: FormControl<number>;
+          nc: FormControl<number>;
+          display: FormControl<number | null>;
+          ageing: FormControl<number | null>;
+        }>
+      >([]),
+    });
+
+    this.products = this.form.controls.product.valueChanges.pipe(
+      debounceTime(150),
+      distinctUntilChanged(),
+      switchMap((x) => (x === null ? observableOf([]) : this.productSer.autocompleteSku(x, null))),
+    );
+  }
+
+  ngOnInit() {
+    this.route.data.subscribe((value) => {
+      const data = value as { info: MozimoProductRegister };
+      this.info = data.info;
+      this.form.patchValue({
+        product: this.info.product?.name ?? '',
+        startDate: moment(this.info.startDate, 'DD-MMM-YYYY').toDate(),
+        finishDate: moment(this.info.finishDate, 'DD-MMM-YYYY').toDate(),
+      });
+      this.form.controls.items.clear();
+      this.info.body.forEach((x) =>
+        this.form.controls.items.push(
+          new FormGroup({
+            received: new FormControl(x.received, { nonNullable: true, validators: [Validators.min(0)] }),
+            sale: new FormControl(x.sale, { nonNullable: true, validators: [Validators.min(0)] }),
+            nc: new FormControl(x.nc, { nonNullable: true, validators: [Validators.min(0)] }),
+            display: new FormControl(x.display, { nonNullable: false, validators: [Validators.min(0)] }),
+            ageing: new FormControl(x.ageing, { nonNullable: false, validators: [Validators.min(0)] }),
+          }),
+        ),
+      );
+      if (!this.dataSource.paginator) {
+        this.dataSource.paginator = this.paginator;
+      }
+      this.body.next(this.info.body);
+    });
+  }
+
+  displayFn(product?: Product | string): string {
+    return !product ? '' : typeof product === 'string' ? product : product.name;
+  }
+
+  selected(event: MatAutocompleteSelectedEvent): void {
+    this.info.product = event.option.value;
+  }
+
+  show() {
+    const info = this.getInfo();
+    if (info.product) {
+      this.router.navigate(['mozimo-product-register', info.product.id], {
+        queryParams: {
+          startDate: info.startDate,
+          finishDate: info.finishDate,
+        },
+      });
+    }
+  }
+
+  save() {
+    this.ser.save(this.getMozimoProductRegister()).subscribe({
+      next: () => {
+        this.snackBar.open('', 'Success');
+      },
+      error: (error) => {
+        this.snackBar.open(error, 'Danger');
+      },
+    });
+  }
+
+  getMozimoProductRegister(): MozimoProductRegister {
+    const formModel = this.form.value;
+    this.info.startDate = moment(formModel.startDate).format('DD-MMM-YYYY');
+    this.info.finishDate = moment(formModel.finishDate).format('DD-MMM-YYYY');
+
+    const array = this.form.controls.items;
+    this.info.body.forEach((item, index) => {
+      item.received = +(array.controls[index].value.received ?? 0);
+      item.sale = +(array.controls[index].value.sale ?? 0);
+      item.nc = +(array.controls[index].value.nc ?? 0);
+      const display = array.controls[index].value.display ?? null;
+      const ageing = array.controls[index].value.ageing ?? null;
+      item.display = display == null ? null : +display;
+      item.ageing = ageing == null ? null : +ageing;
+    });
+    return this.info;
+  }
+
+  getInfo(): MozimoProductRegister {
+    const formModel = this.form.value;
+
+    return new MozimoProductRegister({
+      product: this.info.product,
+      startDate: moment(formModel.startDate).format('DD-MMM-YYYY'),
+      finishDate: moment(formModel.finishDate).format('DD-MMM-YYYY'),
+    });
+  }
+
+  exportCsv() {
+    const headers = {
+      Date: 'date',
+      Opening: 'opening',
+      Received: 'received',
+      Sale: 'sale',
+    };
+
+    const d = JSON.parse(JSON.stringify(this.dataSource.data)).map((x: MozimoProductRegisterItem) => ({
+      x,
+    }));
+    const csvData = new Blob([this.toCsv.toCsv(headers, d)], {
+      type: 'text/csv;charset=utf-8;',
+    });
+    const link = document.createElement('a');
+    link.href = window.URL.createObjectURL(csvData);
+    link.setAttribute('download', 'mozimo-product-register.csv');
+    document.body.appendChild(link);
+    link.click();
+    document.body.removeChild(link);
+  }
+
+  updateReceived($event: Event, row: MozimoProductRegisterItem) {
+    row.received = +($event.target as HTMLInputElement).value;
+    this.body.next(this.info.body);
+  }
+
+  updateSale($event: Event, row: MozimoProductRegisterItem) {
+    row.sale = +($event.target as HTMLInputElement).value;
+    this.body.next(this.info.body);
+  }
+
+  updateNc($event: Event, row: MozimoProductRegisterItem) {
+    row.nc = +($event.target as HTMLInputElement).value;
+    this.body.next(this.info.body);
+  }
+
+  updateDisplay($event: Event, row: MozimoProductRegisterItem) {
+    const val = ($event.target as HTMLInputElement).value;
+    row.display = val === '' ? null : +val;
+    this.body.next(this.info.body);
+  }
+
+  updateAgeing($event: Event, row: MozimoProductRegisterItem) {
+    const val = ($event.target as HTMLInputElement).value;
+    row.ageing = val === '' ? null : +val;
+    this.body.next(this.info.body);
+  }
+}
diff --git a/overlord/src/app/mozimo-product-register/mozimo-product-register.resolver.spec.ts b/overlord/src/app/mozimo-product-register/mozimo-product-register.resolver.spec.ts
new file mode 100644
index 00000000..d7750b7e
--- /dev/null
+++ b/overlord/src/app/mozimo-product-register/mozimo-product-register.resolver.spec.ts
@@ -0,0 +1,18 @@
+import { TestBed } from '@angular/core/testing';
+import { ResolveFn } from '@angular/router';
+
+import { MozimoProductRegister } from './mozimo-product-register';
+import { mozimoProductRegisterResolver } from './mozimo-product-register.resolver';
+
+describe('mozimoProductRegisterResolver', () => {
+  const executeResolver: ResolveFn<MozimoProductRegister> = (...resolverParameters) =>
+    TestBed.runInInjectionContext(() => mozimoProductRegisterResolver(...resolverParameters));
+
+  beforeEach(() => {
+    TestBed.configureTestingModule({});
+  });
+
+  it('should be created', () => {
+    expect(executeResolver).toBeTruthy();
+  });
+});
diff --git a/overlord/src/app/mozimo-product-register/mozimo-product-register.resolver.ts b/overlord/src/app/mozimo-product-register/mozimo-product-register.resolver.ts
new file mode 100644
index 00000000..8a9b9ddd
--- /dev/null
+++ b/overlord/src/app/mozimo-product-register/mozimo-product-register.resolver.ts
@@ -0,0 +1,12 @@
+import { inject } from '@angular/core';
+import { ResolveFn } from '@angular/router';
+
+import { MozimoProductRegister } from './mozimo-product-register';
+import { MozimoProductRegisterService } from './mozimo-product-register.service';
+
+export const mozimoProductRegisterResolver: ResolveFn<MozimoProductRegister> = (route) => {
+  const id = route.paramMap.get('id');
+  const startDate = route.queryParamMap.get('startDate') || null;
+  const finishDate = route.queryParamMap.get('finishDate') || null;
+  return inject(MozimoProductRegisterService).list(id, startDate, finishDate);
+};
diff --git a/overlord/src/app/mozimo-product-register/mozimo-product-register.routes.ts b/overlord/src/app/mozimo-product-register/mozimo-product-register.routes.ts
new file mode 100644
index 00000000..d71dae18
--- /dev/null
+++ b/overlord/src/app/mozimo-product-register/mozimo-product-register.routes.ts
@@ -0,0 +1,34 @@
+import { Routes } from '@angular/router';
+
+import { authGuard } from '../auth/auth-guard.service';
+
+import { MozimoProductRegisterComponent } from './mozimo-product-register.component';
+import { mozimoProductRegisterResolver } from './mozimo-product-register.resolver';
+
+export const routes: Routes = [
+  {
+    path: '',
+    component: MozimoProductRegisterComponent,
+    canActivate: [authGuard],
+    data: {
+      permission: 'Ledger',
+    },
+    resolve: {
+      info: mozimoProductRegisterResolver,
+    },
+    runGuardsAndResolvers: 'always',
+  },
+  {
+    path: ':id',
+    component: MozimoProductRegisterComponent,
+    canActivate: [authGuard],
+    data: {
+      // permission: 'Mozimo Product Register',
+      permission: 'Ledger',
+    },
+    resolve: {
+      info: mozimoProductRegisterResolver,
+    },
+    runGuardsAndResolvers: 'always',
+  },
+];
diff --git a/overlord/src/app/mozimo-product-register/mozimo-product-register.service.spec.ts b/overlord/src/app/mozimo-product-register/mozimo-product-register.service.spec.ts
new file mode 100644
index 00000000..d558638d
--- /dev/null
+++ b/overlord/src/app/mozimo-product-register/mozimo-product-register.service.spec.ts
@@ -0,0 +1,17 @@
+import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http';
+import { inject, TestBed } from '@angular/core/testing';
+
+import { MozimoProductRegisterService } from './mozimo-product-register.service';
+
+describe('MozimoProductRegisterService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      imports: [],
+      providers: [MozimoProductRegisterService, provideHttpClient(withInterceptorsFromDi())],
+    });
+  });
+
+  it('should be created', inject([MozimoProductRegisterService], (service: MozimoProductRegisterService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/overlord/src/app/mozimo-product-register/mozimo-product-register.service.ts b/overlord/src/app/mozimo-product-register/mozimo-product-register.service.ts
new file mode 100644
index 00000000..9c09a651
--- /dev/null
+++ b/overlord/src/app/mozimo-product-register/mozimo-product-register.service.ts
@@ -0,0 +1,55 @@
+import { HttpClient, HttpParams } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs/internal/Observable';
+import { catchError } from 'rxjs/operators';
+
+import { ErrorLoggerService } from '../core/error-logger.service';
+
+import { MozimoProductRegister } from './mozimo-product-register';
+
+const url = '/api/mozimo-product-register';
+const serviceName = 'MozimoProductRegisterService';
+
+@Injectable({
+  providedIn: 'root',
+})
+export class MozimoProductRegisterService {
+  constructor(
+    private http: HttpClient,
+    private log: ErrorLoggerService,
+  ) {}
+
+  list(id: string | null, startDate: string | null, finishDate: string | null): Observable<MozimoProductRegister> {
+    const listUrl = id === null ? url : `${url}/${id}`;
+    const options = { params: new HttpParams() };
+    if (startDate !== null) {
+      options.params = options.params.set('s', startDate);
+    }
+    if (finishDate !== null) {
+      options.params = options.params.set('f', finishDate);
+    }
+    return this.http
+      .get<MozimoProductRegister>(listUrl, options)
+      .pipe(catchError(this.log.handleError(serviceName, 'list'))) as Observable<MozimoProductRegister>;
+  }
+
+  save(mozimoProductRegister: MozimoProductRegister): Observable<MozimoProductRegister> {
+    return this.http
+      .post<MozimoProductRegister>(url, mozimoProductRegister)
+      .pipe(catchError(this.log.handleError(serviceName, 'save'))) as Observable<MozimoProductRegister>;
+  }
+
+  post(date: string, costCentre: string): Observable<MozimoProductRegister> {
+    const options = { params: new HttpParams().set('d', costCentre) };
+    return this.http
+      .post<MozimoProductRegister>(`${url}/${date}`, {}, options)
+      .pipe(catchError(this.log.handleError(serviceName, 'Post Voucher'))) as Observable<MozimoProductRegister>;
+  }
+
+  delete(date: string, costCentre: string): Observable<MozimoProductRegister> {
+    const options = { params: new HttpParams().set('d', costCentre) };
+    return this.http
+      .delete<MozimoProductRegister>(`${url}/${date}`, options)
+      .pipe(catchError(this.log.handleError(serviceName, 'Delete Voucher'))) as Observable<MozimoProductRegister>;
+  }
+}
diff --git a/overlord/src/app/mozimo-product-register/mozimo-product-register.ts b/overlord/src/app/mozimo-product-register/mozimo-product-register.ts
new file mode 100644
index 00000000..98e14340
--- /dev/null
+++ b/overlord/src/app/mozimo-product-register/mozimo-product-register.ts
@@ -0,0 +1,18 @@
+import { Product } from '../core/product';
+
+import { MozimoProductRegisterItem } from './mozimo-product-register-item';
+
+export class MozimoProductRegister {
+  startDate: string;
+  finishDate: string;
+  product: Product;
+  body: MozimoProductRegisterItem[];
+
+  public constructor(init?: Partial<MozimoProductRegister>) {
+    this.startDate = '';
+    this.finishDate = '';
+    this.product = new Product();
+    this.body = [];
+    Object.assign(this, init);
+  }
+}