Compare commits

..
6 Commits
Author SHA1 Message Date
tanshu 9a3bd413d6 Version Bump v11.2.0 2023-08-08 13:07:00 +05:30
tanshu 2fa346e084 Fix: Fingerprints should have the right constraint
Fix: Client list was not working
2023-08-08 13:06:42 +05:30
tanshu ecd3e45632 Version Bump v11.1.9 2023-08-07 12:48:02 +05:30
tanshu 48ec2df10d Fix: Fingerprint was ignoring the time aspect which is obviously very important 2023-08-07 12:47:57 +05:30
tanshu bc61eeacd3 Version Bump v11.1.8 2023-08-07 10:58:49 +05:30
tanshu a051071a1b Fix: Fingerprint upload was broken 2023-08-07 10:58:41 +05:30
10 changed files with 45 additions and 27 deletions
@@ -0,0 +1,24 @@
"""FP
Revision ID: 48af31eb6f3f
Revises: 12262aadbc08
Create Date: 2023-08-07 13:01:05.401492
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql
# revision identifiers, used by Alembic.
revision = '48af31eb6f3f'
down_revision = '12262aadbc08'
branch_labels = None
depends_on = None
def upgrade():
op.create_unique_constraint(op.f('uq_fingerprints_date'), 'fingerprints', ['date', 'employee_id'])
def downgrade():
op.drop_constraint(op.f('uq_fingerprints_date'), 'fingerprints', type_='unique')
+1 -1
View File
@@ -1 +1 @@
__version__ = "11.1.7" __version__ = "11.2.0"
+2 -1
View File
@@ -3,7 +3,7 @@ import uuid
from datetime import datetime from datetime import datetime
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from sqlalchemy import DateTime, ForeignKey, Uuid from sqlalchemy import DateTime, ForeignKey, UniqueConstraint, Uuid
from sqlalchemy.orm import Mapped, mapped_column, relationship from sqlalchemy.orm import Mapped, mapped_column, relationship
from ..db.base_class import reg from ..db.base_class import reg
@@ -16,6 +16,7 @@ if TYPE_CHECKING:
@reg.mapped_as_dataclass(unsafe_hash=True) @reg.mapped_as_dataclass(unsafe_hash=True)
class Fingerprint: class Fingerprint:
__tablename__ = "fingerprints" __tablename__ = "fingerprints"
__table_args__ = (UniqueConstraint("date", "employee_id"),)
id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4) id: Mapped[uuid.UUID] = mapped_column(Uuid, primary_key=True, insert_default=uuid.uuid4)
employee_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("employees.id"), nullable=False) employee_id: Mapped[uuid.UUID] = mapped_column(Uuid, ForeignKey("employees.id"), nullable=False)
+5 -14
View File
@@ -8,7 +8,7 @@ from io import StringIO
import brewman.schemas.fingerprint as schemas import brewman.schemas.fingerprint as schemas
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status
from sqlalchemy import bindparam, select from sqlalchemy import select
from sqlalchemy.dialects.postgresql import insert as pg_insert from sqlalchemy.dialects.postgresql import insert as pg_insert
from sqlalchemy.exc import SQLAlchemyError from sqlalchemy.exc import SQLAlchemyError
from sqlalchemy.orm import Session from sqlalchemy.orm import Session
@@ -36,22 +36,13 @@ def upload_prints(
for id_, code in db.execute(select(Employee.id, Employee.code)).all(): for id_, code in db.execute(select(Employee.id, Employee.code)).all():
employees[code] = id_ employees[code] = id_
file_data = read_file(fingerprints) file_data = read_file(fingerprints)
prints = [d for d in fp(file_data, employees) if start <= d.date_.date() <= finish] prints = [d.model_dump() for d in fp(file_data, employees) if start <= d.date_.date() <= finish]
for p in prints:
p["id"] = p.pop("id_")
paged_data = [prints[i : i + 100] for i in range(0, len(prints), 100)] paged_data = [prints[i : i + 100] for i in range(0, len(prints), 100)]
for i, page in enumerate(paged_data): for i, page in enumerate(paged_data):
print(f"Processing page {i} of {len(paged_data)}") print(f"Processing page {i} of {len(paged_data)}")
db.execute( db.execute(pg_insert(Fingerprint).on_conflict_do_nothing(), page)
pg_insert(Fingerprint)
.values(
{
"id": bindparam("id"),
"employee_id": bindparam("employee_id"),
"date": bindparam("date"),
}
)
.on_conflict_do_nothing(),
[p.dict() for p in page],
)
db.commit() db.commit()
except SQLAlchemyError as e: except SQLAlchemyError as e:
raise HTTPException( raise HTTPException(
+5 -3
View File
@@ -44,11 +44,13 @@ class ClientList(Client):
@field_validator("last_date", mode="before") @field_validator("last_date", mode="before")
@classmethod @classmethod
def parse_last_date(cls, value: datetime | str) -> datetime | None: def parse_last_date(cls, value: datetime | str | None) -> datetime | None:
if value is None or value == "":
return None
if isinstance(value, datetime): if isinstance(value, datetime):
return value return value
return datetime.strptime(value, "%d-%b-%Y %H:%M") return datetime.strptime(value, "%d-%b-%Y %H:%M")
@field_serializer("last_date") @field_serializer("last_date")
def serialize_last_date(self, value: datetime, info: FieldSerializationInfo) -> str: def serialize_last_date(self, value: datetime | None, info: FieldSerializationInfo) -> str | None:
return value.strftime("%d-%b-%Y %H:%M") return None if value is None else value.strftime("%d-%b-%Y %H:%M")
+4 -4
View File
@@ -20,11 +20,11 @@ class Fingerprint(BaseModel):
@field_validator("date_", mode="before") @field_validator("date_", mode="before")
@classmethod @classmethod
def parse_date(cls, value: date | str) -> date: def parse_date(cls, value: datetime | str) -> datetime:
if isinstance(value, date): if isinstance(value, datetime):
return value return value
return datetime.strptime(value, "%d-%b-%Y").date() return datetime.strptime(value, "%d-%b-%Y %H:%M")
@field_serializer("date_") @field_serializer("date_")
def serialize_date(self, value: date, info: FieldSerializationInfo) -> str: def serialize_date(self, value: date, info: FieldSerializationInfo) -> str:
return value.strftime("%d-%b-%Y") return value.strftime("%d-%b-%Y %H:%M")
+1 -1
View File
@@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "brewman" name = "brewman"
version = "11.1.7" version = "11.2.0"
description = "Accounting plus inventory management for a restaurant." description = "Accounting plus inventory management for a restaurant."
authors = ["tanshu <git@tanshu.com>"] authors = ["tanshu <git@tanshu.com>"]
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "overlord", "name": "overlord",
"version": "11.1.7", "version": "11.2.0",
"scripts": { "scripts": {
"ng": "ng", "ng": "ng",
"start": "ng serve", "start": "ng serve",
@@ -2,5 +2,5 @@ export const environment = {
production: true, production: true,
// eslint-disable-next-line @typescript-eslint/naming-convention // eslint-disable-next-line @typescript-eslint/naming-convention
ACCESS_TOKEN_REFRESH_MINUTES: 10, // refresh token 10 minutes before expiry ACCESS_TOKEN_REFRESH_MINUTES: 10, // refresh token 10 minutes before expiry
version: '11.1.7', version: '11.2.0',
}; };
+1 -1
View File
@@ -6,7 +6,7 @@ export const environment = {
production: false, production: false,
// eslint-disable-next-line @typescript-eslint/naming-convention // eslint-disable-next-line @typescript-eslint/naming-convention
ACCESS_TOKEN_REFRESH_MINUTES: 10, // refresh token 10 minutes before expiry ACCESS_TOKEN_REFRESH_MINUTES: 10, // refresh token 10 minutes before expiry
version: '11.1.7', version: '11.2.0',
}; };
/* /*