Skip to content

Commit 59f8644

Browse files
committed
new Vat number validations
1 parent 909dae9 commit 59f8644

13 files changed

+480
-63
lines changed

CLAUDE.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
This is a Laravel package that provides custom validation rules, factory helpers, and services primarily focused on Swedish localization. The package includes validation rules for Swedish business/personal numbers, phone numbers, bank accounts, and VAT IDs.
8+
9+
## Architecture
10+
11+
### Core Components
12+
13+
- **Rules**: Custom Laravel validation rules in `src/Rules/`
14+
- **Factories**: Faker providers for generating test data in `src/Factories/`
15+
- **Services**: Business logic services in `src/Services/`
16+
- **Helpers**: Legacy helper functions in `src/Helpers/` and `src/RuleHelpers.php`
17+
18+
### Key Dependencies
19+
20+
- `personnummer/personnummer`: Swedish personal number validation
21+
- `organisationsnummer/organisationsnummer`: Swedish organization number validation
22+
- `brick/phonenumber`: International phone number validation
23+
- `byrokrat/banking`: Swedish banking system validation
24+
- `mpociot/vat-calculator`: EU VAT validation services
25+
- `tanthammar/laravel-extras`: Custom Laravel utilities
26+
27+
### Service Provider
28+
29+
The `LaravelRulesServiceProvider` registers custom validation rules and handles translations:
30+
- Extends basic Laravel validators with Swedish-specific rules
31+
- Registers custom text validation rules: `alpha_space`, `alpha_num_space`, `alpha_dash_space`, etc.
32+
- Handles internationalization for Swedish (`sv`) and English (`en`)
33+
34+
## Rule Architecture
35+
36+
All validation rules follow Laravel's Rule contract and implement both legacy and modern validation patterns:
37+
- Legacy: `passes()` method with `message()` method
38+
- Modern: `validate()` method with closure-based failure handling
39+
40+
### Key Validation Rules
41+
42+
- **PersonNummer**: Swedish personal identification numbers
43+
- **OrgNummer**: Swedish organization numbers
44+
- **VatNumber**: EU VAT ID validation with service availability handling
45+
- **PhoneNumber**: International phone numbers with automatic "+" prefix handling
46+
- **BankGiro/PlusGiro**: Swedish payment system validation
47+
- **BankKonto**: Swedish bank account validation
48+
49+
## Development Workflow
50+
51+
### Installation
52+
```bash
53+
composer require tanthammar/laravel-rules
54+
```
55+
56+
### Usage Pattern
57+
```php
58+
use TantHammar\LaravelRules\Rules\PhoneNumber;
59+
use TantHammar\LaravelRules\Rules\PersonNummer;
60+
61+
$field->rules([new PhoneNumber]);
62+
$field->rules([new PersonNummer]);
63+
```
64+
65+
### Testing Data Generation
66+
Use factory classes for generating Swedish test data:
67+
```php
68+
FakePhoneNumber::make(international: true)
69+
FakePhoneNumber::gdprSafe() // GDPR-compliant test numbers
70+
```
71+
72+
## Services and Deprecation
73+
74+
The package has migrated from static helper methods to dedicated service classes:
75+
- `RuleHelpers::getBusinessNameFromVatID()``BusinessNameFromVatID::lookup()`
76+
- `RuleHelpers::getVATDetailsFromVatID()``VatDetailsFromVatID::lookup()`
77+
- `RuleHelpers::check_business_type()``BusinessTypeFromNr::make()`
78+
79+
## Internationalization
80+
81+
Translations are stored in `resources/lang/` with support for Swedish and English. Error messages are prefixed with `laravel-rules::messages.` for proper namespacing.
82+
83+
## Development Commands
84+
85+
This package does not include test suites, linting, or build scripts. Development is typically done by:
86+
- Installing the package in a Laravel project via `composer require tanthammar/laravel-rules`
87+
- Testing validation rules directly in Laravel applications
88+
- Manual testing of factory helpers and services
89+
90+
## Development Notes
91+
92+
- The package supports PHP 8.1+ and Laravel 10.0+
93+
- External API dependencies (VAT validation) include proper exception handling for service unavailability
94+
- Phone number validation automatically handles missing "+" prefix
95+
- All number inputs are cleaned using `CleanNumber::make()` from the extras package

README.md

Lines changed: 195 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,212 @@
1-
# Missing validation rules and fakers, for Laravel
2-
In this repository I will add validators and factory helpers, that I use in my SaaS app. I think especially Swedish developers will find them handy.
1+
# Laravel Rules & Validators
2+
Custom validation rules, factory helpers, and services for Laravel applications, with a focus on Swedish localization.
33

44
## Requirements
5-
- PHP 8.1
6-
- Laravel v9.0
5+
- PHP 8.1+
6+
- Laravel 10.0+
77

88
## Installation
99
```bash
1010
composer require tanthammar/laravel-rules
1111
```
1212

13-
## Rules, Fakers and more
14-
See src folder
13+
## Validation Rules
1514

16-
## Documentation
17-
There won't be much documentation written, this repository will grow as I add items.
18-
Hopefully the source code contains enough hints to use the components.
15+
### Swedish Personal & Organization Numbers
16+
```php
17+
use TantHammar\LaravelRules\Rules\PersonNummer;
18+
use TantHammar\LaravelRules\Rules\OrgNummer;
19+
use TantHammar\LaravelRules\Rules\PersonOrOrgNummer;
20+
21+
// Swedish personal identification numbers
22+
$request->validate([
23+
'person_number' => [new PersonNummer]
24+
]);
25+
26+
// Swedish organization numbers
27+
$request->validate([
28+
'org_number' => [new OrgNummer]
29+
]);
1930

20-
They are all used in the same way, following Laravel conventions.
31+
// Accept either personal or organization numbers
32+
$request->validate([
33+
'number' => [new PersonOrOrgNummer]
34+
]);
35+
```
2136

22-
Example:
37+
### Phone Numbers
2338
```php
2439
use TantHammar\LaravelRules\Rules\PhoneNumber;
25-
use TantHammar\LaravelRules\Rules\PersonNummer;
40+
use TantHammar\LaravelRules\Rules\MobileNumber;
41+
use TantHammar\LaravelRules\Rules\FixedLineNumber;
42+
43+
// International phone numbers (handles missing + prefix automatically)
44+
$request->validate([
45+
'phone' => [new PhoneNumber]
46+
]);
47+
48+
// Mobile numbers only
49+
$request->validate([
50+
'mobile' => [new MobileNumber]
51+
]);
52+
53+
// Fixed line numbers only
54+
$request->validate([
55+
'landline' => [new FixedLineNumber]
56+
]);
57+
```
58+
59+
### Swedish Banking
60+
```php
61+
use TantHammar\LaravelRules\Rules\BankKonto;
62+
use TantHammar\LaravelRules\Rules\BankGiro;
63+
use TantHammar\LaravelRules\Rules\PlusGiro;
64+
65+
// Swedish bank account numbers
66+
$request->validate([
67+
'bank_account' => [new BankKonto]
68+
]);
69+
70+
// BankGiro payment numbers
71+
$request->validate([
72+
'bankgiro' => [new BankGiro]
73+
]);
74+
75+
// PlusGiro payment numbers
76+
$request->validate([
77+
'plusgiro' => [new PlusGiro]
78+
]);
79+
```
80+
81+
### VAT Number Validation
82+
83+
⚠️ **Important**: Choose the right VAT validation rule based on your needs:
84+
85+
#### VatNumberFormat (Recommended for most cases)
86+
Only validates the format using regex - no external API calls.
87+
```php
88+
use TantHammar\LaravelRules\Rules\VatNumberFormat;
89+
90+
$request->validate([
91+
'vat_number' => [new VatNumberFormat]
92+
]);
93+
```
94+
95+
#### VatNumberAPI (Use with caution)
96+
Validates against the VIES EU API but throws exceptions when service is unavailable.
97+
```php
98+
use TantHammar\LaravelRules\Rules\VatNumberAPI;
99+
use Mpociot\VatCalculator\Exceptions\VATCheckUnavailableException;
100+
101+
try {
102+
$request->validate([
103+
'vat_number' => [new VatNumberAPI]
104+
]);
105+
} catch (VATCheckUnavailableException $e) {
106+
// Handle service unavailability
107+
// Service can be down for hours or days
108+
return back()->withErrors([
109+
'vat_number' => 'VAT validation service is temporarily unavailable. Please try again later.'
110+
]);
111+
}
112+
```
113+
114+
#### VatNumberAPIWithFormatFallback (Balanced approach)
115+
Tries API validation first, falls back to format validation if service is unavailable.
116+
```php
117+
use TantHammar\LaravelRules\Rules\VatNumberAPIWithFormatFallback;
118+
119+
$request->validate([
120+
'vat_number' => [new VatNumberAPIWithFormatFallback]
121+
]);
122+
```
123+
124+
### Geographic Coordinates
125+
```php
126+
use TantHammar\LaravelRules\Rules\Latitude;
127+
use TantHammar\LaravelRules\Rules\Longitude;
128+
129+
$request->validate([
130+
'lat' => [new Latitude],
131+
'lng' => [new Longitude]
132+
]);
133+
```
134+
135+
### File Upload Validation
136+
```php
137+
use TantHammar\LaravelRules\Rules\MaxTotalFileSize;
138+
139+
// Limit total size of all uploaded files
140+
$request->validate([
141+
'documents.*' => ['file'],
142+
'documents' => [new MaxTotalFileSize(5000)] // 5MB total
143+
]);
144+
```
145+
146+
## Factory Helpers
147+
148+
Generate realistic test data for Swedish formats:
149+
150+
```php
151+
use TantHammar\LaravelRules\Factories\FakePhoneNumber;
152+
use TantHammar\LaravelRules\Factories\FakeMobileNumber;
153+
use TantHammar\LaravelRules\Factories\FakeBankgiro;
154+
use TantHammar\LaravelRules\Factories\FakePlusgiro;
155+
156+
// Generate Swedish phone numbers
157+
$phone = FakePhoneNumber::make(international: true);
158+
$localPhone = FakePhoneNumber::make(international: false);
159+
160+
// GDPR-safe phone numbers (official test ranges)
161+
$gdprPhone = FakePhoneNumber::gdprSafe();
162+
163+
// Mobile numbers
164+
$mobile = FakeMobileNumber::make();
165+
166+
// Payment numbers
167+
$bankgiro = FakeBankgiro::make();
168+
$plusgiro = FakePlusgiro::make();
169+
```
170+
171+
## Services
172+
173+
### VAT Information Lookup
174+
```php
175+
use TantHammar\LaravelRules\Services\BusinessNameFromVatID;
176+
use TantHammar\LaravelRules\Services\VatDetailsFromVatID;
177+
178+
// Get business name from VAT ID
179+
$businessName = BusinessNameFromVatID::lookup('SE556556567801');
180+
181+
// Get full VAT details
182+
$details = VatDetailsFromVatID::lookup('SE556556567801');
183+
```
184+
185+
### Business Type Detection
186+
```php
187+
use TantHammar\LaravelRules\Helpers\BusinessTypeFromNr;
188+
189+
// Determine if number is personal, business, or undefined
190+
$type = BusinessTypeFromNr::make('199001011234'); // Returns: 'individual'
191+
$type = BusinessTypeFromNr::make('556556567801'); // Returns: 'business'
192+
$type = BusinessTypeFromNr::make('invalid'); // Returns: 'undefined'
193+
```
194+
195+
## Legacy Helper Methods (Deprecated)
196+
197+
These methods are deprecated but still available for backwards compatibility:
198+
199+
```php
200+
use TantHammar\LaravelRules\RuleHelpers;
201+
202+
// Use BusinessNameFromVatID::lookup() instead
203+
$name = RuleHelpers::getBusinessNameFromVatID($vatId);
204+
205+
// Use VatDetailsFromVatID::lookup() instead
206+
$details = RuleHelpers::getVATDetailsFromVatID($vatId);
26207

27-
SomeField::make('phone')
28-
->rules([ new PhoneNumber ])
29-
SomeField::make('person_nummer')
30-
->rules([ new PersonNummer ])
208+
// Use BusinessTypeFromNr::make() instead
209+
$type = RuleHelpers::check_business_type($number);
31210
```
32211

33212

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"php": "^8.1|^8.2|^8.3|^8.4",
2121
"brick/phonenumber": "^0.8.0",
2222
"byrokrat/banking": "^2.2",
23-
"laravel/framework": "^9.0|^10.0|^11.0|^12.0",
23+
"laravel/framework": "^10.0|^11.0|^12.0",
2424
"personnummer/personnummer": "^3.0.4",
2525
"organisationsnummer/organisationsnummer": "^2.0.0",
2626
"mpociot/vat-calculator": "^3.22.0",

resources/lang/en/messages.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
'latitude' => 'The latitude value is invalid',
1919
'longitude' => 'The longitude value is invalid',
2020
'vat-service-unavailable' => 'Sorry, but the "VIES EU Vat service" is unavailable. Unable to validate your Vat ID. Please try again later or contact support for personal assistance.',
21+
'vies-eu-unavailable' => "VIES EU Vat service is unavailable. Please try again later.",
2122
'vat-invalid' => 'The :attribute is not a valid VAT ID number.',
2223
'vat-name-unknown' => 'Unknown legal name',
2324
'total-file-sizes' => 'The sum of all file sizes should not exeed :kb Kb.',

resources/lang/sv/messages.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
'plusgiro' => 'Du måste ange ett giltigt PlusGiro nummer',
1818
'latitude' => 'Latitude värdet är felaktigt',
1919
'longitude' => 'Longitude värdet är felaktigt',
20-
'vat-service-unavailable' => 'Tyvärr svarar inte "VIES EU Vat test service". Det är därför omöjligt att verifiera ditt Moms-nr. Vänligen försök om en stund igen eller kontakta support för manuell hantering.',
20+
'vat-service-unavailable' => 'Tyvärr svarar inte "VIES EU Vat test service". Det är därför omöjligt att verifiera ditt Moms-nr. Vänligen försök senare eller kontakta support för manuell hantering.',
21+
'vies-eu-unavailable' => "VIES EU Vat service är inte tillgänglig. Vänligen försök senare.",
2122
'vat-invalid' => ':Attribute är ej ett giltigt momsregistreringsnummer',
2223
'vat-name-unknown' => 'Juridiskt namn saknas',
2324
'total-file-sizes' => 'Summan av filernas storlek får inte överstiga :kb Kb.',

0 commit comments

Comments
 (0)