/* This file is part of GNU Taler (C) 2021-2024 Taler Systems S.A. GNU Taler is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see */ /** * * @author Sebastian Javier Marchano (sebasjm) */ import { isAfter, isFuture } from "date-fns"; import * as yup from "yup"; import { AMOUNT_REGEX, PAYTO_REGEX } from "../utils/constants.js"; import { Amounts } from "@gnu-taler/taler-util"; yup.setLocale({ mixed: { default: "field_invalid", }, number: { min: ({ min }: any) => ({ key: "field_too_short", values: { min } }), max: ({ max }: any) => ({ key: "field_too_big", values: { max } }), }, }); function listOfPayToUrisAreValid(values?: (string | undefined)[]): boolean { return !!values && values.every((v) => v && PAYTO_REGEX.test(v)); } function currencyWithAmountIsValid(value?: string): boolean { return !!value && Amounts.parse(value) !== undefined; } function currencyGreaterThan0(value?: string) { if (value) { try { const [, amount] = value.split(":"); const intAmount = parseInt(amount, 10); return intAmount > 0; } catch { return false; } } return true; } export const InstanceSchema = yup.object().shape({ id: yup.string().required().meta({ type: "url" }), name: yup.string().required(), auth: yup.object().shape({ method: yup.string().matches(/^(external|token)$/), token: yup.string().optional().nullable(), }), payto_uris: yup .array() .of(yup.string()) .min(1) .meta({ type: "array" }) .test("payto", "{path} is not valid", listOfPayToUrisAreValid), default_max_deposit_fee: yup .string() .required() .test("amount", "the amount is not valid", currencyWithAmountIsValid) .meta({ type: "amount" }), default_max_wire_fee: yup .string() .required() .test("amount", "{path} is not valid", currencyWithAmountIsValid) .meta({ type: "amount" }), default_wire_fee_amortization: yup.number().required(), address: yup .object() .shape({ country: yup.string().optional(), address_lines: yup.array().of(yup.string()).max(7).optional(), building_number: yup.string().optional(), building_name: yup.string().optional(), street: yup.string().optional(), post_code: yup.string().optional(), town_location: yup.string().optional(), town: yup.string(), district: yup.string().optional(), country_subdivision: yup.string().optional(), }) .meta({ type: "group" }), jurisdiction: yup .object() .shape({ country: yup.string().optional(), address_lines: yup.array().of(yup.string()).max(7).optional(), building_number: yup.string().optional(), building_name: yup.string().optional(), street: yup.string().optional(), post_code: yup.string().optional(), town_location: yup.string().optional(), town: yup.string(), district: yup.string().optional(), country_subdivision: yup.string().optional(), }) .meta({ type: "group" }), // default_pay_delay: yup.object() // .shape({ d_us: yup.number() }) // .required() // .meta({ type: 'duration' }), // .transform(numberToDuration), default_wire_transfer_delay: yup .object() .shape({ d_us: yup.number() }) .required() .meta({ type: "duration" }), // .transform(numberToDuration), }); export const InstanceUpdateSchema = InstanceSchema.clone().omit(["id"]); export const InstanceCreateSchema = InstanceSchema.clone(); export const AuthorizeRewardSchema = yup.object().shape({ justification: yup.string().required(), amount: yup .string() .required() .test("amount", "the amount is not valid", currencyWithAmountIsValid) .test("amount_positive", "the amount is not valid", currencyGreaterThan0), next_url: yup.string().required(), }); const stringIsValidJSON = (value?: string) => { const p = value?.trim(); if (!p) return true; try { JSON.parse(p); return true; } catch { return false; } }; export const OrderCreateSchema = yup.object().shape({ pricing: yup .object() .required() .shape({ summary: yup.string().ensure().required(), order_price: yup .string() .ensure() .required() .test("amount", "the amount is not valid", currencyWithAmountIsValid) .test( "amount_positive", "the amount should be greater than 0", currencyGreaterThan0, ), }), // extra: yup.object().test("extra", "is not a JSON format", stringIsValidJSON), payments: yup .object() .required() .shape({ refund_deadline: yup .date() .test("future", "should be in the future", (d) => d ? isFuture(d) : true, ), pay_deadline: yup .date() .test("future", "should be in the future", (d) => d ? isFuture(d) : true, ), auto_refund_deadline: yup .date() .test("future", "should be in the future", (d) => d ? isFuture(d) : true, ), delivery_date: yup .date() .test("future", "should be in the future", (d) => d ? isFuture(d) : true, ), }) .test("payment", "dates", (d) => { if ( d.pay_deadline && d.refund_deadline && isAfter(d.refund_deadline, d.pay_deadline) ) { return new yup.ValidationError( "pay deadline should be greater than refund", "asd", "payments.pay_deadline", ); } return true; }), }); export const ProductCreateSchema = yup.object().shape({ product_id: yup.string().ensure().required(), description: yup.string().required(), unit: yup.string().ensure().required(), price: yup .string() .required() .test("amount", "the amount is not valid", currencyWithAmountIsValid), stock: yup.object({}).optional(), minimum_age: yup.number().optional().min(0), }); export const ProductUpdateSchema = yup.object().shape({ description: yup.string().required(), price: yup .string() .required() .test("amount", "the amount is not valid", currencyWithAmountIsValid), stock: yup.object({}).optional(), minimum_age: yup.number().optional().min(0), }); export const TaxSchema = yup.object().shape({ name: yup.string().required().ensure(), tax: yup .string() .required() .test("amount", "the amount is not valid", currencyWithAmountIsValid), }); export const NonInventoryProductSchema = yup.object().shape({ quantity: yup.number().required().positive(), description: yup.string().required(), unit: yup.string().ensure().required(), price: yup .string() .required() .test("amount", "the amount is not valid", currencyWithAmountIsValid), });