@@ -54,6 +54,8 @@ const assetSchema = z.object({
5454 currency : z . string ( ) . min ( 1 , 'Valuta è obbligatoria' ) ,
5555 quantity : z . number ( ) . positive ( 'Quantità deve essere positiva' ) ,
5656 manualPrice : z . number ( ) . positive ( 'Il prezzo deve essere positivo' ) . optional ( ) . or ( z . nan ( ) ) ,
57+ averageCost : z . number ( ) . positive ( 'Il costo medio deve essere positivo' ) . optional ( ) . or ( z . nan ( ) ) ,
58+ taxRate : z . number ( ) . min ( 0 , 'L\'aliquota fiscale deve essere almeno 0' ) . max ( 100 , 'L\'aliquota fiscale deve essere massimo 100' ) . optional ( ) . or ( z . nan ( ) ) ,
5759 isLiquid : z . boolean ( ) . optional ( ) ,
5860 autoUpdatePrice : z . boolean ( ) . optional ( ) ,
5961 isComposite : z . boolean ( ) . optional ( ) ,
@@ -98,6 +100,7 @@ export function AssetDialog({ open, onClose, asset }: AssetDialogProps) {
98100 const [ composition , setComposition ] = useState < AssetComposition [ ] > ( [ ] ) ;
99101 const [ isComposite , setIsComposite ] = useState ( false ) ;
100102 const [ hasOutstandingDebt , setHasOutstandingDebt ] = useState ( false ) ;
103+ const [ showCostBasis , setShowCostBasis ] = useState ( false ) ;
101104 const {
102105 register,
103106 handleSubmit,
@@ -190,6 +193,8 @@ export function AssetDialog({ open, onClose, asset }: AssetDialogProps) {
190193 currency : asset . currency ,
191194 quantity : asset . quantity ,
192195 manualPrice : asset . currentPrice > 0 ? asset . currentPrice : undefined ,
196+ averageCost : asset . averageCost || undefined ,
197+ taxRate : asset . taxRate || undefined ,
193198 isLiquid : defaultIsLiquid ,
194199 autoUpdatePrice : asset . autoUpdatePrice !== undefined ? asset . autoUpdatePrice : shouldUpdatePrice ( asset . type , asset . subCategory ) ,
195200 isComposite : ! ! ( asset . composition && asset . composition . length > 0 ) ,
@@ -206,6 +211,9 @@ export function AssetDialog({ open, onClose, asset }: AssetDialogProps) {
206211
207212 // Set hasOutstandingDebt state based on asset data
208213 setHasOutstandingDebt ( ! ! ( asset . outstandingDebt && asset . outstandingDebt > 0 ) ) ;
214+
215+ // Set showCostBasis state based on asset data
216+ setShowCostBasis ( ! ! ( ( asset . averageCost && asset . averageCost > 0 ) || ( asset . taxRate && asset . taxRate > 0 ) ) ) ;
209217 } else {
210218 reset ( {
211219 ticker : '' ,
@@ -216,6 +224,8 @@ export function AssetDialog({ open, onClose, asset }: AssetDialogProps) {
216224 currency : 'EUR' ,
217225 quantity : 0 ,
218226 manualPrice : undefined ,
227+ averageCost : undefined ,
228+ taxRate : undefined ,
219229 isLiquid : true ,
220230 autoUpdatePrice : true ,
221231 isComposite : false ,
@@ -224,6 +234,7 @@ export function AssetDialog({ open, onClose, asset }: AssetDialogProps) {
224234 setComposition ( [ ] ) ;
225235 setIsComposite ( false ) ;
226236 setHasOutstandingDebt ( false ) ;
237+ setShowCostBasis ( false ) ;
227238 }
228239 } , [ asset , reset ] ) ;
229240
@@ -371,6 +382,8 @@ export function AssetDialog({ open, onClose, asset }: AssetDialogProps) {
371382 subCategory : data . subCategory || undefined ,
372383 currency : data . currency ,
373384 quantity : data . quantity ,
385+ averageCost : data . averageCost && ! isNaN ( data . averageCost ) && data . averageCost > 0 ? data . averageCost : undefined ,
386+ taxRate : data . taxRate && ! isNaN ( data . taxRate ) && data . taxRate >= 0 ? data . taxRate : undefined ,
374387 currentPrice,
375388 isLiquid : data . isLiquid ,
376389 autoUpdatePrice : data . autoUpdatePrice ,
@@ -778,6 +791,71 @@ export function AssetDialog({ open, onClose, asset }: AssetDialogProps) {
778791 </ div >
779792 ) }
780793
794+ { /* Cost Basis Tracking */ }
795+ < div className = "space-y-2 rounded-lg border p-4" >
796+ < div className = "flex items-center justify-between" >
797+ < div className = "space-y-0.5" >
798+ < Label htmlFor = "showCostBasis" > Tracciamento Cost Basis</ Label >
799+ < p className = "text-xs text-gray-500" >
800+ Abilita il calcolo di plusvalenze non realizzate e tasse stimate
801+ </ p >
802+ </ div >
803+ < Switch
804+ id = "showCostBasis"
805+ checked = { showCostBasis }
806+ onCheckedChange = { ( checked ) => {
807+ setShowCostBasis ( checked ) ;
808+ if ( ! checked ) {
809+ setValue ( 'averageCost' , undefined ) ;
810+ setValue ( 'taxRate' , undefined ) ;
811+ }
812+ } }
813+ />
814+ </ div >
815+
816+ { showCostBasis && (
817+ < div className = "mt-4 space-y-4" >
818+ < div className = "grid grid-cols-2 gap-4" >
819+ < div className = "space-y-2" >
820+ < Label htmlFor = "averageCost" > Costo Medio per Azione ({ watch ( 'currency' ) } )</ Label >
821+ < Input
822+ id = "averageCost"
823+ type = "number"
824+ step = "0.01"
825+ min = "0"
826+ { ...register ( 'averageCost' , { valueAsNumber : true } ) }
827+ placeholder = "es. 85.50"
828+ />
829+ { errors . averageCost && (
830+ < p className = "text-sm text-red-500" > { errors . averageCost . message } </ p >
831+ ) }
832+ < p className = "text-xs text-gray-500" >
833+ Il costo medio di acquisto per singola azione/unità
834+ </ p >
835+ </ div >
836+ < div className = "space-y-2" >
837+ < Label htmlFor = "taxRate" > Aliquota Fiscale (%)</ Label >
838+ < Input
839+ id = "taxRate"
840+ type = "number"
841+ step = "0.01"
842+ min = "0"
843+ max = "100"
844+ { ...register ( 'taxRate' , { valueAsNumber : true } ) }
845+ placeholder = "es. 26"
846+ />
847+ { errors . taxRate && (
848+ < p className = "text-sm text-red-500" > { errors . taxRate . message } </ p >
849+ ) }
850+ < p className = "text-xs text-gray-500" >
851+ Percentuale di tassazione sulle plusvalenze (es. 26 per 26%)
852+ </ p >
853+ </ div >
854+ </ div >
855+ </ div >
856+ ) }
857+ </ div >
858+
781859 { shouldUpdatePrice ( selectedType , selectedSubCategory ) && (
782860 < div className = "space-y-2" >
783861 < Label htmlFor = "manualPrice" > Prezzo Manuale (opzionale)</ Label >
0 commit comments