Fix: Batch Integrity

Fix: Cash Flow
Fix: Non Contract Purchase
Fix: Stock Movement
Fix: Trial Balance
This commit is contained in:
2025-07-16 07:14:09 +00:00
parent 846a7209ee
commit b1d5ff7df6
9 changed files with 40 additions and 42 deletions

View File

@ -52,10 +52,10 @@ def negative_batches(db: Session) -> list[schemas.BatchIntegrity]:
select(Batch, ProductVersion.name, inv_sum) select(Batch, ProductVersion.name, inv_sum)
.join(Batch.sku) .join(Batch.sku)
.join(StockKeepingUnit.product) .join(StockKeepingUnit.product)
.join(ProductVersion, onclause=product_version_onclause)
.join(Batch.inventories) .join(Batch.inventories)
.join(Inventory.voucher) .join(Inventory.voucher)
.join(Voucher.journals) .join(Voucher.journals)
.join(ProductVersion, onclause=product_version_onclause)
.where( .where(
Journal.cost_centre_id == CostCentre.cost_centre_purchase(), Journal.cost_centre_id == CostCentre.cost_centre_purchase(),
) )
@ -121,9 +121,9 @@ def batch_dates(db: Session) -> list[schemas.BatchIntegrity]:
select(Batch) select(Batch)
.join(Batch.sku) .join(Batch.sku)
.join(StockKeepingUnit.product) .join(StockKeepingUnit.product)
.join(ProductVersion, onclause=product_version_onclause)
.join(Batch.inventories) .join(Batch.inventories)
.join(Inventory.voucher) .join(Inventory.voucher)
.join(ProductVersion, onclause=product_version_onclause)
.where(Voucher.date_ < Batch.name) .where(Voucher.date_ < Batch.name)
.options( .options(
contains_eager(Batch.sku).contains_eager(StockKeepingUnit.product), contains_eager(Batch.sku).contains_eager(StockKeepingUnit.product),

View File

@ -114,15 +114,15 @@ def build_report(
amount=round(amount * -1, 2), amount=round(amount * -1, 2),
) )
) )
cash_id_sq = select(func.distinct(AccountType.id)).where(AccountType.name == "Cash").subquery()
opening: Decimal = db.execute( opening: Decimal = db.execute(
select(func.sum(Journal.amount * Journal.debit)) select(func.sum(Journal.amount * Journal.debit))
.join(Journal.voucher) .join(Journal.voucher)
.join(Journal.account) .join(Journal.account)
.where( .where(
Voucher.date_ < start_date, Voucher.date_ < start_date,
not_(Voucher.voucher_type.in_([VoucherType.ISSUE, VoucherType.CLOSING_STOCK])), Voucher.voucher_type.not_in([VoucherType.ISSUE, VoucherType.CLOSING_STOCK]),
AccountBase.type_id == select(AccountType.id).where(AccountType.name == "Cash"), AccountBase.type_id == cash_id_sq,
) )
).scalar() or Decimal(0) ).scalar() or Decimal(0)
@ -132,8 +132,8 @@ def build_report(
.join(Journal.account) .join(Journal.account)
.where( .where(
Voucher.date_ <= finish_date, Voucher.date_ <= finish_date,
not_(Voucher.voucher_type.in_([VoucherType.ISSUE, VoucherType.CLOSING_STOCK])), Voucher.voucher_type.not_in([VoucherType.ISSUE, VoucherType.CLOSING_STOCK]),
AccountBase.type_id == select(AccountType.id).where(AccountType.name == "Cash"), AccountBase.type_id == cash_id_sq,
) )
).scalar() or Decimal(0) ).scalar() or Decimal(0)

View File

@ -1,6 +1,6 @@
from fastapi import APIRouter, Security from fastapi import APIRouter, Security
from sqlalchemy import and_, or_, select from sqlalchemy import and_, or_, select
from sqlalchemy.orm import Session, contains_eager, joinedload from sqlalchemy.orm import Session, contains_eager
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 SessionFuture from ...db.session import SessionFuture
@ -36,9 +36,7 @@ def report(db: Session) -> list[schemas.NonContractPurchase]:
.join(RateContract.vendor) .join(RateContract.vendor)
.join(RateContract.items) .join(RateContract.items)
.options( .options(
joinedload(RateContract.items, innerjoin=True),
contains_eager(RateContract.items), contains_eager(RateContract.items),
joinedload(RateContract.vendor, innerjoin=True),
contains_eager(RateContract.vendor), contains_eager(RateContract.vendor),
) )
) )

View File

@ -2,8 +2,8 @@ from datetime import date, datetime
from decimal import Decimal from decimal import Decimal
from fastapi import APIRouter, Request, Security from fastapi import APIRouter, Request, Security
from sqlalchemy import and_, not_, or_ from sqlalchemy import and_, or_
from sqlalchemy.orm import Session, contains_eager from sqlalchemy.orm import Session
from sqlalchemy.sql.expression import func, select from sqlalchemy.sql.expression import func, select
from ...core.security import get_current_active_user as get_user from ...core.security import get_current_active_user as get_user
@ -89,12 +89,6 @@ def build_stock_movement(start_date: date, finish_date: date, db: Session) -> li
.join(StockKeepingUnit.product) .join(StockKeepingUnit.product)
.join(ProductVersion, onclause=product_version_onclause) .join(ProductVersion, onclause=product_version_onclause)
.join(ProductVersion.product_group) .join(ProductVersion.product_group)
.options(
contains_eager(SkuVersion.sku)
.contains_eager(StockKeepingUnit.product)
.contains_eager(Product.versions)
.contains_eager(ProductVersion.product_group)
)
.where(Voucher.date_ < start_date, Journal.cost_centre_id == CostCentre.cost_centre_purchase()) .where(Voucher.date_ < start_date, Journal.cost_centre_id == CostCentre.cost_centre_purchase())
.group_by(StockKeepingUnit, Product, ProductVersion, ProductGroup, SkuVersion) # type: ignore .group_by(StockKeepingUnit, Product, ProductVersion, ProductGroup, SkuVersion) # type: ignore
).all() ).all()
@ -120,16 +114,10 @@ def build_stock_movement(start_date: date, finish_date: date, db: Session) -> li
.join(StockKeepingUnit.product) .join(StockKeepingUnit.product)
.join(ProductVersion, onclause=product_version_onclause) .join(ProductVersion, onclause=product_version_onclause)
.join(ProductVersion.product_group) .join(ProductVersion.product_group)
.options(
contains_eager(SkuVersion.sku)
.contains_eager(StockKeepingUnit.product)
.contains_eager(Product.versions)
.contains_eager(ProductVersion.product_group)
)
.where( .where(
Voucher.date_ >= start_date, Voucher.date_ >= start_date,
Voucher.date_ <= finish_date, Voucher.date_ <= finish_date,
not_(Voucher.voucher_type.in_([VoucherType.ISSUE, VoucherType.CLOSING_STOCK])), Voucher.voucher_type.not_in([VoucherType.ISSUE, VoucherType.CLOSING_STOCK]),
Journal.cost_centre_id == CostCentre.cost_centre_purchase(), Journal.cost_centre_id == CostCentre.cost_centre_purchase(),
) )
.group_by(StockKeepingUnit, Product, ProductVersion, ProductGroup, SkuVersion) # type: ignore .group_by(StockKeepingUnit, Product, ProductVersion, ProductGroup, SkuVersion) # type: ignore
@ -159,12 +147,6 @@ def build_stock_movement(start_date: date, finish_date: date, db: Session) -> li
.join(StockKeepingUnit.product) .join(StockKeepingUnit.product)
.join(ProductVersion, onclause=product_version_onclause) .join(ProductVersion, onclause=product_version_onclause)
.join(ProductVersion.product_group) .join(ProductVersion.product_group)
.options(
contains_eager(SkuVersion.sku)
.contains_eager(StockKeepingUnit.product)
.contains_eager(Product.versions)
.contains_eager(ProductVersion.product_group)
)
.where( .where(
Voucher.date_ >= start_date, Voucher.date_ >= start_date,
Voucher.date_ <= finish_date, Voucher.date_ <= finish_date,

View File

@ -1,8 +1,7 @@
from datetime import date, datetime from datetime import date, datetime
from fastapi import APIRouter, Request, Security from fastapi import APIRouter, Request, Security
from sqlalchemy import not_ from sqlalchemy.orm import Session, contains_eager
from sqlalchemy.orm import Session, contains_eager, joinedload
from sqlalchemy.sql.expression import func, select from sqlalchemy.sql.expression import func, select
from ...core.security import get_current_active_user as get_user from ...core.security import get_current_active_user as get_user
@ -51,12 +50,11 @@ def build_report(date_: date, db: Session) -> list[schemas.TrialBalanceItem]:
.join(AccountBase.type_) .join(AccountBase.type_)
.where( .where(
Voucher.date_ <= date_, Voucher.date_ <= date_,
not_(Voucher.voucher_type.in_([VoucherType.ISSUE, VoucherType.CLOSING_STOCK])), Voucher.voucher_type.not_in([VoucherType.ISSUE, VoucherType.CLOSING_STOCK]),
) )
.group_by(AccountBase, AccountType) # type: ignore .group_by(AccountBase, AccountType) # type: ignore
.order_by(AccountBase.type_id, func.abs(amount_sum).desc()) .order_by(AccountBase.type_id, func.abs(amount_sum).desc())
.options( .options(
joinedload(AccountBase.type_, innerjoin=True),
contains_eager(AccountBase.type_), contains_eager(AccountBase.type_),
) )
).all() ).all()

View File

@ -1,3 +1,3 @@
.basic-container { // .basic-container {
padding: 30px; // padding: 30px;
} // }

View File

@ -1,5 +1,5 @@
import { LayoutModule } from '@angular/cdk/layout'; import { LayoutModule } from '@angular/cdk/layout';
import { provideHttpClient, withInterceptors } from '@angular/common/http'; import { provideHttpClient, withInterceptors, withFetch } from '@angular/common/http';
import { ApplicationConfig, importProvidersFrom, LOCALE_ID, provideZonelessChangeDetection } from '@angular/core'; import { ApplicationConfig, importProvidersFrom, LOCALE_ID, provideZonelessChangeDetection } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms'; import { ReactiveFormsModule } from '@angular/forms';
import { MomentDateAdapter } from '@angular/material-moment-adapter'; import { MomentDateAdapter } from '@angular/material-moment-adapter';
@ -51,7 +51,7 @@ export const appConfig: ApplicationConfig = {
), ),
{ provide: LOCALE_ID, useValue: 'en-IN' }, { provide: LOCALE_ID, useValue: 'en-IN' },
AuthService, AuthService,
provideHttpClient(withInterceptors([refreshInterceptor, jwtInterceptor, authInterceptor])), provideHttpClient(withFetch(), withInterceptors([refreshInterceptor, jwtInterceptor, authInterceptor])),
provideAnimations(), provideAnimations(),
provideRouter( provideRouter(
routes, routes,

View File

@ -1,6 +1,15 @@
import { SelectionModel } from '@angular/cdk/collections'; import { SelectionModel } from '@angular/cdk/collections';
import { AsyncPipe, CurrencyPipe } from '@angular/common'; import { AsyncPipe, CurrencyPipe } from '@angular/common';
import { AfterViewInit, Component, ElementRef, HostListener, inject, OnInit, ViewChild } from '@angular/core'; import {
AfterViewInit,
Component,
ElementRef,
HostListener,
inject,
OnInit,
ViewChild,
ChangeDetectorRef,
} from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms'; import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
@ -66,6 +75,7 @@ export class LedgerComponent implements OnInit, AfterViewInit {
private toCsv = inject(ToCsvService); private toCsv = inject(ToCsvService);
private accountSer = inject(AccountService); private accountSer = inject(AccountService);
private tagSer = inject(TagService); private tagSer = inject(TagService);
private cd = inject(ChangeDetectorRef);
@ViewChild('accountElement', { static: true }) accountElement!: ElementRef<HTMLInputElement>; @ViewChild('accountElement', { static: true }) accountElement!: ElementRef<HTMLInputElement>;
@ViewChild('startDateElement', { static: true }) startDate!: ElementRef<HTMLInputElement>; @ViewChild('startDateElement', { static: true }) startDate!: ElementRef<HTMLInputElement>;
@ -139,6 +149,7 @@ export class LedgerComponent implements OnInit, AfterViewInit {
this.dataSource.sort = this.sort; this.dataSource.sort = this.sort;
} }
this.selection.clear(); this.selection.clear();
this.cd.detectChanges();
}); });
} }

View File

@ -1,5 +1,6 @@
import { CurrencyPipe } from '@angular/common'; import { CurrencyPipe } from '@angular/common';
import { Component, inject, OnInit, ViewChild } from '@angular/core'; import { Component, inject, OnInit, ViewChild } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator'; import { MatPaginator, MatPaginatorModule } from '@angular/material/paginator';
import { MatSort, MatSortModule } from '@angular/material/sort'; import { MatSort, MatSortModule } from '@angular/material/sort';
@ -13,7 +14,15 @@ import { RateContractListDatasource } from './rate-contract-list-datasource';
selector: 'app-rate-contract-list', selector: 'app-rate-contract-list',
templateUrl: './rate-contract-list.component.html', templateUrl: './rate-contract-list.component.html',
styleUrls: ['./rate-contract-list.component.css'], styleUrls: ['./rate-contract-list.component.css'],
imports: [RouterModule, MatIconModule, MatTableModule, MatSortModule, MatPaginatorModule, CurrencyPipe], imports: [
RouterModule,
MatIconModule,
MatTableModule,
MatSortModule,
MatPaginatorModule,
CurrencyPipe,
MatButtonModule,
],
}) })
export class RateContractListComponent implements OnInit { export class RateContractListComponent implements OnInit {
private route = inject(ActivatedRoute); private route = inject(ActivatedRoute);