hash from ChatGpt

This commit is contained in:
Artur Kuś 2025-02-08 14:11:18 +01:00
parent c2d310ab62
commit 8569fc5310
2 changed files with 108 additions and 168 deletions

View File

@ -7,233 +7,172 @@ import { FormsModule } from '@angular/forms';
import { MatDatepicker, MatDatepickerModule } from '@angular/material/datepicker'; import { MatDatepicker, MatDatepickerModule } from '@angular/material/datepicker';
import { MatNativeDateModule } from '@angular/material/core'; import { MatNativeDateModule } from '@angular/material/core';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { format, parse, addMonths, isAfter } from 'date-fns'; import { format, parse } from 'date-fns';
import { createHash } from 'crypto';
interface FormValues { class AssetLifeChangeWrapper {
initialValueAsset:number; when = signal<string>(YearMonth.todayTxt());
rate: number; initial = signal<number>(0);
startDepreciation: Date;
typeDepreciation: TypeDepreciation;
factor: number;
}
class AssetLifeChangeWrapper{
when = signal<string> ( YearMonth.todayTxt()); constructor(assetLifeChange: AssetLifeChange) {
initial = signal<number>( 0 );
constructor( assetLifeChange : AssetLifeChange ){
this.set(assetLifeChange); this.set(assetLifeChange);
} }
get(): AssetLifeChange { get(): AssetLifeChange {
const ym = this.when(); return new AssetLifeChange(YearMonth.from(this.when()), this.initial(), 0, 0);
const when = YearMonth.from( ym );
return new AssetLifeChange( when, this.initial() , 0, 0 );
} }
set(assetLifeChange: AssetLifeChange) { set(assetLifeChange: AssetLifeChange) {
this.when.set(YearMonth.toTxt(assetLifeChange.when)); this.when.set(YearMonth.toTxt(assetLifeChange.when));
this.initial.set(assetLifeChange.initial); this.initial.set(assetLifeChange.initial);
} }
} }
const NAME_IN_STORAGE = 'assetForCalculator';
const STORAGE_KEY = 'assetForCalculator';
const CACHE_KEY = 'cachedResults';
const HASH_KEY = 'assetHash';
@Component({ @Component({
selector: 'app-asset-calculator', selector: 'app-asset-calculator',
standalone: true, standalone: true,
imports: [DecimalPipe, TranslateModule, FormsModule, MatDatepickerModule, MatNativeDateModule, MatInputModule], imports: [DecimalPipe, TranslateModule, FormsModule, MatDatepickerModule, MatNativeDateModule, MatInputModule],
providers: [ providers: [MatDatepickerModule, MatNativeDateModule],
MatDatepickerModule,
MatNativeDateModule
],
templateUrl: "asset-calculator.component.html", templateUrl: "asset-calculator.component.html",
styleUrls: ['asset-calculator.component.css'] styleUrls: ['asset-calculator.component.css']
}) })
export class AssetCalculatorComponent { export class AssetCalculatorComponent {
TypeDepreciation = TypeDepreciation; TypeDepreciation = TypeDepreciation;
// Signals for form state and amortizations initialValueAsset = signal<number>(6000);
rate = signal<number>(20);
startDepreciation = signal<Date>(new Date());
typeDepreciation = signal<TypeDepreciation>(TypeDepreciation.linear);
factor = signal<number>(2);
lifeChangesSignal = signal<AssetLifeChangeWrapper[]>([]);
amortizationsSignal = signal<AssetPlanPosition[]>([]);
initialValueAsset = signal <number> ( 6000 ); constructor(private assetService: AssetService, private translate: TranslateService) {}
rate = signal <number> ( 20 );
startDepreciation = signal <Date> ( new Date() );
typeDepreciation = signal <TypeDepreciation>( TypeDepreciation.linear );
factor = signal <number>( 2 );
formValues = computed<FormValues>(() => { ngOnInit(): void {
return {
initialValueAsset: this.initialValueAsset(),
rate: this.rate(),
startDepreciation: this.startDepreciation(),
typeDepreciation: this.typeDepreciation(),
factor: this.factor(),
};
});
lifeChangesSignal = signal<AssetLifeChangeWrapper[]>([]); // Replaces `lifeFormArray`
amortizationsSignal =signal<AssetPlanPosition[]>([]);
constructor( private assetService: AssetService,
private translate : TranslateService ) {
// Effect to recalculate when form values change
effect( () => this.reCalculate( ) )
}
private storage = {
load: (key: string) => {
try {
const data = localStorage.getItem(key);
return data ? JSON.parse(data) : null;
} catch {
console.error(`Failed to load ${key} from localStorage`);
return null;
}
},
save: (key: string, data: any) => {
try {
localStorage.setItem(key, JSON.stringify(data));
} catch {
console.error(`Failed to save ${key} to localStorage`);
}
}
};
ngOnInit(): void{
this.restoreState(); this.restoreState();
} }
ngOnDestroy(): void { ngOnDestroy(): void {
const asset = this.controlsToAsset( ); this.saveState(this.controlsToAsset());
if( null != asset){
this.saveState( asset );
}
} }
private restoreState() { private restoreState() {
const savedAsset = this.storage.load(NAME_IN_STORAGE); const savedAsset = localStorage.getItem(STORAGE_KEY);
if (savedAsset) this.assetToControls(savedAsset); const savedResults = localStorage.getItem(CACHE_KEY);
const savedHash = localStorage.getItem(HASH_KEY);
if (savedAsset) {
const asset: Asset = JSON.parse(savedAsset);
this.assetToControls(asset);
// Generujemy nowy hash
const newHash = this.generateHash(asset);
// Jeśli hash jest taki sam, ładujemy wyniki z cache
if (savedHash === newHash && savedResults) {
this.amortizationsSignal.set(JSON.parse(savedResults));
console.log("✅ Załadowano wyniki z cache brak przeliczeń.");
return;
}
console.log("🔄 Hash zmieniony wykonuję przeliczenie.");
this.reCalculate();
}
} }
private saveState(asset: Asset) { private saveState(asset: Asset) {
this.storage.save(NAME_IN_STORAGE, asset); localStorage.setItem(STORAGE_KEY, JSON.stringify(asset));
localStorage.setItem(HASH_KEY, this.generateHash(asset)); // Zapisujemy nowy hash
} }
private assetToControls( asset : Asset ) { private assetToControls(asset: Asset) {
if( asset.life.length > 0 ){ if (!asset.life.length) return;
this.updateBatch(asset); const [firstLife, ...restLives] = asset.life;
} const method = asset.depreciationMethods[0];
}
private updateBatch(asset: Asset) { this.initialValueAsset.set(firstLife.initial);
const [firstLife, ...restLives] = asset.life; this.startDepreciation.set(YearMonth.toDate(firstLife.when));
const method0 = asset.depreciationMethods[0]; this.rate.set(method.rate);
this.typeDepreciation.set(method.type);
this.factor.set(method.factor);
this.lifeChangesSignal.set(restLives.map(life => new AssetLifeChangeWrapper(life)));
}
this.initialValueAsset.set(firstLife.initial); private controlsToAsset(): Asset {
this.startDepreciation.set(YearMonth.toDate(firstLife.when)); const when = YearMonth.fromDate(this.startDepreciation());
this.rate.set(method0.rate); const asset = new Asset(when);
this.typeDepreciation.set(method0.type); const method = new AssetDepreciationMethod(when.year, this.rate(), this.typeDepreciation(), this.factor());
this.factor.set(method0.factor);
const lifeChanges = restLives.map((lifeChange) => asset.addMethod(method);
new AssetLifeChangeWrapper(lifeChange) asset.addChange(new AssetLifeChange(when, this.initialValueAsset(), 0, 0));
); this.lifeChangesSignal().forEach(lc => asset.addChange(lc.get()));
this.lifeChangesSignal.set(lifeChanges);
}
private controlsToAsset(): Asset { return asset;
}
const formValues = this.formValues();
const lifeChanges = this.lifeChangesSignal();
const when = YearMonth.fromDate( formValues.startDepreciation ); private calculateToValues(positions: AssetPlanPosition[]) {
const asset = new Asset( when ); let sum = 0, sumThisYear = 0;
const method = new AssetDepreciationMethod( when.year, formValues.rate, formValues.typeDepreciation, formValues.factor ); positions.forEach(pos => {
asset.addMethod( method ); pos.calculatedDepreciation *= 0.01;
sum += pos.calculatedDepreciation;
pos.sum = sum;
sumThisYear = pos.when.month === 1 ? pos.calculatedDepreciation : sumThisYear + pos.calculatedDepreciation;
pos.sumThisYear = sumThisYear;
});
const creationLifeChange = new AssetLifeChange( when, formValues.initialValueAsset, 0, 0 ); // Cache wyników
asset.addChange( creationLifeChange ); localStorage.setItem(CACHE_KEY, JSON.stringify(positions));
}
lifeChanges.forEach((lifeChange) => {
asset.addChange( lifeChange.get() );
});
return asset;
}
private calculateToValues( positions:AssetPlanPosition[] ) {
let sum = 0;
let sumThisYear = 0;
positions.forEach( position => {
// From gr to zł or from cents to dollars it depends from currency
position.calculatedDepreciation *= 0.01;
sum += position.calculatedDepreciation;
position.sum = sum;
if( position.when.month === 1 ) {
sumThisYear = position.calculatedDepreciation;
} else {
sumThisYear += position.calculatedDepreciation;
}
position.sumThisYear = sumThisYear;
});
}
private reCalculate() { private reCalculate() {
this.calculateAmortizationsForAsset(this.controlsToAsset());
const asset = this.controlsToAsset( );
this.calculateAmortizationsForAsset(asset);
this.saveState(asset);
} }
private calculateAmortizationsForAsset(asset: Asset) { private calculateAmortizationsForAsset(asset: Asset) {
this.assetService.calculate(asset).subscribe((positions) => { this.assetService.calculate(asset).subscribe(positions => {
this.calculateToValues(positions); this.calculateToValues(positions);
this.amortizationsSignal.set(positions); this.amortizationsSignal.set(positions);
}); });
} }
clazz(pos: AssetPlanPosition) {
clazz(pos : AssetPlanPosition ){ return pos.when.year % 2 === 0 ? "table-light" : "table-dark";
return pos.when.year % 2 === 0 ? "table-light" : "table-dark";
} }
// Method to add a life change addLifeChange(amount = 1000) {
addLifeChange( ) { const change = new AssetLifeChange(YearMonth.fromDate(this.startDepreciation()), amount, 0, 0);
const assetLifeChange2 : AssetLifeChange this.lifeChangesSignal.update(changes => [...changes, new AssetLifeChangeWrapper(change)]);
= new AssetLifeChange( YearMonth.fromDate( this.formValues().startDepreciation ), 1000, 0, 0 );
return this.addLifeChange2( assetLifeChange2 );
} }
addLifeChange2( assetLifeChange : AssetLifeChange ) {
const newChangeWrapper = new AssetLifeChangeWrapper( assetLifeChange );
this.lifeChangesSignal.update((changes) => [...changes, newChangeWrapper]);
return newChangeWrapper;
}
// Method to remove a life change
removeLifeChange(index: number) { removeLifeChange(index: number) {
this.lifeChangesSignal.update((changes) => this.lifeChangesSignal.update(changes => changes.filter((_, i) => i !== index));
changes.filter((_, i) => i !== index)
);
} }
updateDateFromInput(inputValue: string) { updateDateFromInput(inputValue: string) {
// Konwersja stringa 'YYYY-MM' na Date this.startDepreciation.set(parse(inputValue, 'yyyy-MM', new Date()));
const parsedDate = parse(inputValue, 'yyyy-MM', new Date());
this.startDepreciation.set(parsedDate);
} }
onMonthSelected(event: Date, datepicker: MatDatepicker<Date>) {
this.startDepreciation.set(event); // Aktualizacja pola w formularzu onMonthSelected(event: Date, datepicker: any) {
this.startDepreciation.set(event);
datepicker.close(); datepicker.close();
} }
}
private generateHash(asset: Asset): string {
const data = JSON.stringify({
initialValue: asset.life[0]?.initial,
rate: asset.depreciationMethods[0]?.rate,
type: asset.depreciationMethods[0]?.type,
factor: asset.depreciationMethods[0]?.factor,
lifeChanges: asset.life.map(lc => ({ when: lc.when, initial: lc.initial }))
});
return createHash('sha256').update(data).digest('hex');
}
}

View File

@ -93,11 +93,12 @@ export class FixedAssetComponent {
private controlsToAssets(): [string, Asset][] { private controlsToAssets(): [string, Asset][] {
const assets = new Map<string, Asset>(); const assets = new Map<string, Asset>();
const today = YearMonth.today();
this.assetFormArray.controls.forEach( control => { this.assetFormArray.controls.forEach( control => {
const nrInv = control.get('nrInv')?.value; const nrInv = control.get('nrInv')?.value;
const initialValue = control.get('initialValue')?.value; const initialValue = control.get('initialValue')?.value;
const yearMonth = YearMonth.today(); const yearMonth = today;
const asset = new Asset( yearMonth ); const asset = new Asset( yearMonth );
const assetLifeChange = new AssetLifeChange( yearMonth, initialValue, 0, 0 ); const assetLifeChange = new AssetLifeChange( yearMonth, initialValue, 0, 0 );
asset.addChange( assetLifeChange ); asset.addChange( assetLifeChange );
@ -117,11 +118,11 @@ export class FixedAssetComponent {
this.addRow( "NrInv" + FixedAssetComponent.indexNr++, 1000 ); this.addRow( "NrInv" + FixedAssetComponent.indexNr++, 1000 );
} }
addRow( nrInv_:string, initial_: number ):void{ addRow( nrInv:string, initial: number ):void{
const newRow = this.fb.group({ const newRow = this.fb.group({
nrInv : [ nrInv_ ], nrInv : [ nrInv ],
initialValue : [ initial_ ], initialValue : [ initial ],
}); });
// typeDepreciation : [ TypeDepreciation.linear ], // typeDepreciation : [ TypeDepreciation.linear ],