*/ public static function all(): array { return [ self::STANDARD => __( 'Standard rate', 'easy-invoice' ), self::ZERO => __( 'Zero rated', 'easy-invoice' ), self::EXEMPT => __( 'Exempt from tax', 'easy-invoice' ), self::REVERSE_CHARGE => __( 'Reverse charge', 'easy-invoice' ), self::INTRA_COMMUNITY => __( 'Intra-community supply', 'easy-invoice' ), self::EXPORT => __( 'Export, tax not charged', 'easy-invoice' ), self::OUT_OF_SCOPE => __( 'Outside the scope of tax', 'easy-invoice' ), ]; } /** * Is this a code we recognise? * * @param string $code Category code. * @return bool */ public static function isValid( string $code ): bool { return array_key_exists( $code, self::all() ); } /** * Human label for a code, falling back to the code itself. * * @param string $code Category code. * @return string */ public static function label( string $code ): string { $all = self::all(); return $all[ $code ] ?? $code; } /** * Does this category charge tax at all? * * Everything except the standard rate resolves to a zero tax amount, but for * different reasons — which is precisely why the reason has to be recorded * separately from the number. * * @param string $code Category code. * @return bool */ public static function isTaxable( string $code ): bool { return self::STANDARD === $code; } /** * Does the standard require a stated reason alongside this category? * * EN 16931 rule BR-E-10 and its siblings: an exempt, reverse-charge, * intra-community, export or out-of-scope line must carry an exemption * reason. An invoice that zero-rates tax without saying why is rejected. * * @param string $code Category code. * @return bool */ public static function requiresReason( string $code ): bool { return in_array( $code, [ self::EXEMPT, self::REVERSE_CHARGE, self::INTRA_COMMUNITY, self::EXPORT, self::OUT_OF_SCOPE ], true ); } /** * The wording that has to appear on the document for a given category. * * These are the customary legal phrases. A merchant can override any of them * through `easy_invoice_tax_exemption_reason`, because the exact wording is * sometimes prescribed locally. * * @param string $code Category code. * @return string Empty when the category needs no statement. */ public static function defaultReason( string $code ): string { switch ( $code ) { case self::REVERSE_CHARGE: $reason = __( 'Reverse charge — VAT to be accounted for by the recipient.', 'easy-invoice' ); break; case self::INTRA_COMMUNITY: $reason = __( 'Intra-community supply — exempt under Article 138 of Directive 2006/112/EC.', 'easy-invoice' ); break; case self::EXPORT: $reason = __( 'Export outside the EU — zero rated.', 'easy-invoice' ); break; case self::EXEMPT: $reason = __( 'Exempt from VAT.', 'easy-invoice' ); break; case self::OUT_OF_SCOPE: $reason = __( 'Outside the scope of VAT.', 'easy-invoice' ); break; default: $reason = ''; } /** * Filter the statement printed for a tax category. * * @param string $reason Default wording. * @param string $code Category code. */ return (string) apply_filters( 'easy_invoice_tax_exemption_reason', $reason, $code ); } }