Fix: Reset stock was not working because:

1. The frontend did not set the date format and that mangled the date string sent
 2. Backend was broken and was not acceping data in json format

Fix: Ledger would occasionally crap out due to rounding and floating point madness, removed the rounding limitation
This commit is contained in:
2020-09-20 09:56:35 +05:30
parent cb66700157
commit 005d45032f
6 changed files with 70 additions and 40 deletions

View File

@ -1,6 +1,4 @@
import uuid import uuid
from datetime import datetime
from decimal import Decimal
from fastapi import ( from fastapi import (
APIRouter, APIRouter,
@ -15,6 +13,7 @@ from ..models.master import Product, CostCentre, AccountBase
from ..schemas.auth import UserToken from ..schemas.auth import UserToken
from ..core.security import get_current_active_user as get_user from ..core.security import get_current_active_user as get_user
from ..db.session import SessionLocal from ..db.session import SessionLocal
from ..schemas.settings import ResetStock
router = APIRouter() router = APIRouter()
@ -31,22 +30,16 @@ def get_db() -> Session:
@router.post("/{id_}") @router.post("/{id_}")
def rebase( def rebase(
id_: uuid.UUID, id_: uuid.UUID,
quantity: Decimal, item: ResetStock,
stockDate: str,
resetDate: str,
db: Session = Depends(get_db), db: Session = Depends(get_db),
user: UserToken = Security(get_user, scopes=["reset-stock"]), user: UserToken = Security(get_user, scopes=["reset-stock"]),
): ):
product: Product = db.query(Product).filter(Product.id == id_).first() product: Product = db.query(Product).filter(Product.id == id_).first()
quantity = round(quantity, 2) if item.reset_date > item.stock_date:
stock_date = datetime.strptime(stockDate, "%d-%b-%Y").date()
reset_date = datetime.strptime(resetDate, "%d-%b-%Y").date()
if reset_date > stock_date:
raise ValueError("Reset cannot be after the stock date") raise ValueError("Reset cannot be after the stock date")
change = quantity - get_closing_stock(product, stock_date, db=db) change = round(item.quantity, 2) - get_closing_stock(product, item.stock_date, db=db)
if change == 0: if change == 0:
return {"No Change Needed"} return {"No Change Needed"}
final = get_closing_stock(product, db=db) final = get_closing_stock(product, db=db)
@ -56,7 +49,7 @@ def rebase(
batch = get_last_batch(product, db) batch = get_last_batch(product, db)
set_batches(batch, final + change, db) set_batches(batch, final + change, db)
create_voucher(batch, change, reset_date, user.id_, db) create_voucher(batch, change, item.reset_date, user.id_, db)
db.commit() db.commit()
return {} return {}

View File

@ -15,8 +15,8 @@ class LedgerItem(BaseModel):
url: List[str] url: List[str]
type_: str type_: str
narration: str narration: str
debit: Decimal = Field(multiple_of=0.01) debit: Decimal
credit: Decimal = Field(multiple_of=0.01) credit: Decimal
posted: bool posted: bool
@validator("date_", pre=True) @validator("date_", pre=True)

View File

@ -1,5 +1,5 @@
import uuid from decimal import Decimal
from typing import List, Optional from typing import Optional
from datetime import datetime, date from datetime import datetime, date
from pydantic import BaseModel, validator from pydantic import BaseModel, validator
@ -38,3 +38,27 @@ class LockInformation(BaseModel):
class Maintenance(BaseModel): class Maintenance(BaseModel):
enabled: bool enabled: bool
user: Optional[str] user: Optional[str]
class ResetStock(BaseModel):
quantity: Decimal
stock_date: date
reset_date: date
class Config:
alias_generator = to_camel
json_encoders = {
date: lambda v: v.strftime("%d-%b-%Y"),
}
@validator("stock_date", pre=True)
def parse_stock_date(cls, value):
if isinstance(value, date):
return value
return datetime.strptime(value, "%d-%b-%Y").date()
@validator("reset_date", pre=True)
def parse_reset_date(cls, value):
if isinstance(value, date):
return value
return datetime.strptime(value, "%d-%b-%Y").date()

View File

@ -90,10 +90,6 @@ export class AuthService {
return Date.now() > (this.user.exp - (environment.ACCESS_TOKEN_REFRESH_MINUTES * 60)) * 1000; return Date.now() > (this.user.exp - (environment.ACCESS_TOKEN_REFRESH_MINUTES * 60)) * 1000;
} }
expired(): boolean {
return Date.now() > this.user.exp * 1000;
}
logout() { logout() {
// remove user from local storage to log user out // remove user from local storage to log user out
localStorage.removeItem(JWT_USER); localStorage.removeItem(JWT_USER);

View File

@ -1,5 +1,5 @@
import {NgModule} from '@angular/core'; import { NgModule } from '@angular/core';
import {CommonModule} from '@angular/common'; import { CommonModule } from '@angular/common';
import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card'; import { MatCardModule } from '@angular/material/card';
@ -13,14 +13,14 @@ import { MatPaginatorModule } from '@angular/material/paginator';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatSortModule } from '@angular/material/sort'; import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import {SharedModule} from '../shared/shared.module'; import { SharedModule } from '../shared/shared.module';
import {ReactiveFormsModule} from '@angular/forms'; import { ReactiveFormsModule } from '@angular/forms';
import {CdkTableModule} from '@angular/cdk/table'; import { CdkTableModule } from '@angular/cdk/table';
import {LedgerRoutingModule} from './ledger-routing.module'; import { LedgerRoutingModule } from './ledger-routing.module';
import {LedgerComponent} from './ledger.component'; import { LedgerComponent } from './ledger.component';
import {MomentDateAdapter} from '@angular/material-moment-adapter'; import { MomentDateAdapter } from '@angular/material-moment-adapter';
import {A11yModule} from '@angular/cdk/a11y'; import { A11yModule } from '@angular/cdk/a11y';
import {FlexLayoutModule} from '@angular/flex-layout'; import { FlexLayoutModule } from '@angular/flex-layout';
export const MY_FORMATS = { export const MY_FORMATS = {
parse: { parse: {

View File

@ -1,10 +1,10 @@
import {NgModule} from '@angular/core'; import { NgModule } from '@angular/core';
import {CommonModule} from '@angular/common'; import { CommonModule } from '@angular/common';
import { MatAutocompleteModule } from '@angular/material/autocomplete'; import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card'; import { MatCardModule } from '@angular/material/card';
import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatNativeDateModule } from '@angular/material/core'; import {DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatNativeDateModule} from '@angular/material/core';
import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatDialogModule } from '@angular/material/dialog'; import { MatDialogModule } from '@angular/material/dialog';
import { MatFormFieldModule } from '@angular/material/form-field'; import { MatFormFieldModule } from '@angular/material/form-field';
@ -16,13 +16,26 @@ import { MatSelectModule } from '@angular/material/select';
import { MatSortModule } from '@angular/material/sort'; import { MatSortModule } from '@angular/material/sort';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { MatTabsModule } from '@angular/material/tabs'; import { MatTabsModule } from '@angular/material/tabs';
import {ReactiveFormsModule} from '@angular/forms'; import { ReactiveFormsModule } from '@angular/forms';
import {CdkTableModule} from '@angular/cdk/table'; import { CdkTableModule } from '@angular/cdk/table';
import {A11yModule} from '@angular/cdk/a11y'; import { A11yModule } from '@angular/cdk/a11y';
import {FlexLayoutModule} from '@angular/flex-layout'; import { FlexLayoutModule } from '@angular/flex-layout';
import {SharedModule} from '../shared/shared.module'; import { SharedModule } from '../shared/shared.module';
import {SettingsComponent} from './settings.component'; import { SettingsComponent } from './settings.component';
import {SettingsRoutingModule} from './settings-routing.module'; import { SettingsRoutingModule } from './settings-routing.module';
import {MomentDateAdapter} from "@angular/material-moment-adapter";
export const MY_FORMATS = {
parse: {
dateInput: 'DD-MMM-YYYY',
},
display: {
dateInput: 'DD-MMM-YYYY',
monthYearLabel: 'MMM YYYY',
dateA11yLabel: 'DD-MMM-YYYY',
monthYearA11yLabel: 'MMM YYYY',
},
};
@NgModule({ @NgModule({
imports: [ imports: [
@ -52,6 +65,10 @@ import {SettingsRoutingModule} from './settings-routing.module';
], ],
declarations: [ declarations: [
SettingsComponent SettingsComponent
],
providers: [
{provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE]},
{provide: MAT_DATE_FORMATS, useValue: MY_FORMATS},
] ]
}) })
export class SettingsModule { export class SettingsModule {