hash from ChatGpt
This commit is contained in:
parent
c2d310ab62
commit
8569fc5310
|
|
@ -7,18 +7,11 @@ import { FormsModule } from '@angular/forms';
|
|||
import { MatDatepicker, MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatNativeDateModule } from '@angular/material/core';
|
||||
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 {
|
||||
initialValueAsset:number;
|
||||
rate: number;
|
||||
startDepreciation: Date;
|
||||
typeDepreciation: TypeDepreciation;
|
||||
factor: number;
|
||||
}
|
||||
class AssetLifeChangeWrapper {
|
||||
|
||||
when = signal<string>(YearMonth.todayTxt());
|
||||
initial = signal<number>(0);
|
||||
|
||||
|
|
@ -27,213 +20,159 @@ class AssetLifeChangeWrapper{
|
|||
}
|
||||
|
||||
get(): AssetLifeChange {
|
||||
const ym = this.when();
|
||||
const when = YearMonth.from( ym );
|
||||
return new AssetLifeChange( when, this.initial() , 0, 0 );
|
||||
return new AssetLifeChange(YearMonth.from(this.when()), this.initial(), 0, 0);
|
||||
}
|
||||
|
||||
set(assetLifeChange: AssetLifeChange) {
|
||||
this.when.set(YearMonth.toTxt(assetLifeChange.when));
|
||||
this.initial.set(assetLifeChange.initial);
|
||||
}
|
||||
|
||||
}
|
||||
const NAME_IN_STORAGE = 'assetForCalculator';
|
||||
|
||||
const STORAGE_KEY = 'assetForCalculator';
|
||||
const CACHE_KEY = 'cachedResults';
|
||||
const HASH_KEY = 'assetHash';
|
||||
|
||||
@Component({
|
||||
selector: 'app-asset-calculator',
|
||||
standalone: true,
|
||||
imports: [DecimalPipe, TranslateModule, FormsModule, MatDatepickerModule, MatNativeDateModule, MatInputModule],
|
||||
providers: [
|
||||
MatDatepickerModule,
|
||||
MatNativeDateModule
|
||||
],
|
||||
providers: [MatDatepickerModule, MatNativeDateModule],
|
||||
templateUrl: "asset-calculator.component.html",
|
||||
styleUrls: ['asset-calculator.component.css']
|
||||
})
|
||||
export class AssetCalculatorComponent {
|
||||
|
||||
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);
|
||||
|
||||
formValues = computed<FormValues>(() => {
|
||||
return {
|
||||
initialValueAsset: this.initialValueAsset(),
|
||||
rate: this.rate(),
|
||||
startDepreciation: this.startDepreciation(),
|
||||
typeDepreciation: this.typeDepreciation(),
|
||||
factor: this.factor(),
|
||||
};
|
||||
});
|
||||
|
||||
lifeChangesSignal = signal<AssetLifeChangeWrapper[]>([]); // Replaces `lifeFormArray`
|
||||
|
||||
lifeChangesSignal = signal<AssetLifeChangeWrapper[]>([]);
|
||||
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`);
|
||||
}
|
||||
}
|
||||
};
|
||||
constructor(private assetService: AssetService, private translate: TranslateService) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.restoreState();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
const asset = this.controlsToAsset( );
|
||||
if( null != asset){
|
||||
this.saveState( asset );
|
||||
}
|
||||
this.saveState(this.controlsToAsset());
|
||||
}
|
||||
|
||||
private restoreState() {
|
||||
const savedAsset = this.storage.load(NAME_IN_STORAGE);
|
||||
if (savedAsset) this.assetToControls(savedAsset);
|
||||
const savedAsset = localStorage.getItem(STORAGE_KEY);
|
||||
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) {
|
||||
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) {
|
||||
if( asset.life.length > 0 ){
|
||||
this.updateBatch(asset);
|
||||
}
|
||||
}
|
||||
|
||||
private updateBatch(asset: Asset) {
|
||||
if (!asset.life.length) return;
|
||||
const [firstLife, ...restLives] = asset.life;
|
||||
const method0 = asset.depreciationMethods[0];
|
||||
const method = asset.depreciationMethods[0];
|
||||
|
||||
this.initialValueAsset.set(firstLife.initial);
|
||||
this.startDepreciation.set(YearMonth.toDate(firstLife.when));
|
||||
this.rate.set(method0.rate);
|
||||
this.typeDepreciation.set(method0.type);
|
||||
this.factor.set(method0.factor);
|
||||
|
||||
const lifeChanges = restLives.map((lifeChange) =>
|
||||
new AssetLifeChangeWrapper(lifeChange)
|
||||
);
|
||||
this.lifeChangesSignal.set(lifeChanges);
|
||||
this.rate.set(method.rate);
|
||||
this.typeDepreciation.set(method.type);
|
||||
this.factor.set(method.factor);
|
||||
this.lifeChangesSignal.set(restLives.map(life => new AssetLifeChangeWrapper(life)));
|
||||
}
|
||||
|
||||
private controlsToAsset(): Asset {
|
||||
|
||||
const formValues = this.formValues();
|
||||
const lifeChanges = this.lifeChangesSignal();
|
||||
|
||||
const when = YearMonth.fromDate( formValues.startDepreciation );
|
||||
const when = YearMonth.fromDate(this.startDepreciation());
|
||||
const asset = new Asset(when);
|
||||
const method = new AssetDepreciationMethod(when.year, this.rate(), this.typeDepreciation(), this.factor());
|
||||
|
||||
const method = new AssetDepreciationMethod( when.year, formValues.rate, formValues.typeDepreciation, formValues.factor );
|
||||
asset.addMethod(method);
|
||||
|
||||
const creationLifeChange = new AssetLifeChange( when, formValues.initialValueAsset, 0, 0 );
|
||||
asset.addChange( creationLifeChange );
|
||||
|
||||
lifeChanges.forEach((lifeChange) => {
|
||||
asset.addChange( lifeChange.get() );
|
||||
});
|
||||
asset.addChange(new AssetLifeChange(when, this.initialValueAsset(), 0, 0));
|
||||
this.lifeChangesSignal().forEach(lc => asset.addChange(lc.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;
|
||||
let sum = 0, sumThisYear = 0;
|
||||
|
||||
if( position.when.month === 1 ) {
|
||||
sumThisYear = position.calculatedDepreciation;
|
||||
} else {
|
||||
sumThisYear += position.calculatedDepreciation;
|
||||
}
|
||||
position.sumThisYear = sumThisYear;
|
||||
positions.forEach(pos => {
|
||||
pos.calculatedDepreciation *= 0.01;
|
||||
sum += pos.calculatedDepreciation;
|
||||
pos.sum = sum;
|
||||
sumThisYear = pos.when.month === 1 ? pos.calculatedDepreciation : sumThisYear + pos.calculatedDepreciation;
|
||||
pos.sumThisYear = sumThisYear;
|
||||
});
|
||||
|
||||
// Cache wyników
|
||||
localStorage.setItem(CACHE_KEY, JSON.stringify(positions));
|
||||
}
|
||||
|
||||
private reCalculate() {
|
||||
|
||||
const asset = this.controlsToAsset( );
|
||||
this.calculateAmortizationsForAsset(asset);
|
||||
this.saveState(asset);
|
||||
|
||||
this.calculateAmortizationsForAsset(this.controlsToAsset());
|
||||
}
|
||||
|
||||
private calculateAmortizationsForAsset(asset: Asset) {
|
||||
this.assetService.calculate(asset).subscribe((positions) => {
|
||||
this.assetService.calculate(asset).subscribe(positions => {
|
||||
this.calculateToValues(positions);
|
||||
this.amortizationsSignal.set(positions);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
clazz(pos: AssetPlanPosition) {
|
||||
return pos.when.year % 2 === 0 ? "table-light" : "table-dark";
|
||||
}
|
||||
|
||||
// Method to add a life change
|
||||
addLifeChange( ) {
|
||||
const assetLifeChange2 : AssetLifeChange
|
||||
= new AssetLifeChange( YearMonth.fromDate( this.formValues().startDepreciation ), 1000, 0, 0 );
|
||||
return this.addLifeChange2( assetLifeChange2 );
|
||||
|
||||
addLifeChange(amount = 1000) {
|
||||
const change = new AssetLifeChange(YearMonth.fromDate(this.startDepreciation()), amount, 0, 0);
|
||||
this.lifeChangesSignal.update(changes => [...changes, new AssetLifeChangeWrapper(change)]);
|
||||
}
|
||||
|
||||
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) {
|
||||
this.lifeChangesSignal.update((changes) =>
|
||||
changes.filter((_, i) => i !== index)
|
||||
);
|
||||
this.lifeChangesSignal.update(changes => changes.filter((_, i) => i !== index));
|
||||
}
|
||||
|
||||
updateDateFromInput(inputValue: string) {
|
||||
// Konwersja stringa 'YYYY-MM' na Date
|
||||
const parsedDate = parse(inputValue, 'yyyy-MM', new Date());
|
||||
this.startDepreciation.set(parsedDate);
|
||||
this.startDepreciation.set(parse(inputValue, 'yyyy-MM', new Date()));
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -93,11 +93,12 @@ export class FixedAssetComponent {
|
|||
private controlsToAssets(): [string, Asset][] {
|
||||
|
||||
const assets = new Map<string, Asset>();
|
||||
const today = YearMonth.today();
|
||||
this.assetFormArray.controls.forEach( control => {
|
||||
|
||||
const nrInv = control.get('nrInv')?.value;
|
||||
const initialValue = control.get('initialValue')?.value;
|
||||
const yearMonth = YearMonth.today();
|
||||
const yearMonth = today;
|
||||
const asset = new Asset( yearMonth );
|
||||
const assetLifeChange = new AssetLifeChange( yearMonth, initialValue, 0, 0 );
|
||||
asset.addChange( assetLifeChange );
|
||||
|
|
@ -117,11 +118,11 @@ export class FixedAssetComponent {
|
|||
this.addRow( "NrInv" + FixedAssetComponent.indexNr++, 1000 );
|
||||
}
|
||||
|
||||
addRow( nrInv_:string, initial_: number ):void{
|
||||
addRow( nrInv:string, initial: number ):void{
|
||||
|
||||
const newRow = this.fb.group({
|
||||
nrInv : [ nrInv_ ],
|
||||
initialValue : [ initial_ ],
|
||||
nrInv : [ nrInv ],
|
||||
initialValue : [ initial ],
|
||||
});
|
||||
|
||||
// typeDepreciation : [ TypeDepreciation.linear ],
|
||||
|
|
|
|||
Loading…
Reference in New Issue