diff --git a/.github/CHECKLIST.md b/.github/CHECKLIST.md index 23c9c2ec9..a8fe3a41a 100644 --- a/.github/CHECKLIST.md +++ b/.github/CHECKLIST.md @@ -1,12 +1,12 @@ # InvoicePlane V2 – Feature Test Checklist -I've written some tests. Indexes first. After indexes, the statuses, etc. After that the special cases, exceptions, etc., then the Create, Update, Delete actions within the different *modules*. -Some *modules* had a *sub page*. For example: Invoices have invoice_groups as a *sub page*. +I've written some tests. Indexes first. After indexes, the statuses, etc. After that the special cases, exceptions, etc., then the Create, Update, Delete actions within the different *modules*. +Some *modules* had a *sub page*. For example: Invoices have invoice_groups as a *sub page*. Maybe I'll do the *settings* per module as a separate row in this checklist. ## Notes (Invoices) - Tests for overdue invoices are missing: - - If status NOT IN (1,4) and DATEDIFF((NOW), invoice_date_due) > 0 then `is_overdue` is true + - If status NOT IN (1,4) and DATEDIFF((NOW), invoice_date_due) > 0 then `is_overdue` is true - Make special scope for overdue invoices - Test for that scope @@ -18,39 +18,39 @@ Maybe I'll do the *settings* per module as a separate row in this checklist. ## Test Coverage -| Module | Submodule | Index (happy) | Specials (happy) | Create (happy) | Update (happy) | Delete (happy) | Translations | +| Module | Submodule | Index (happy) | Specials (happy) | Create (happy) | Update (happy) | Delete (happy) | Translations | |-----------|------------------|:-------------:|:----------------:|:--------------:|:--------------:|:--------------:|:------------:| -| clients | | ✔️ | | ✔️ | ✔️ | | | -| | user_clients | | | ✔️ | ✔️ | | | -| core | | | | ✔️ | ✔️ | | | -| | custom_fields | | | ✔️ | ✔️ | | | -| | custom_values | | | ✔️ | ✔️ | | | -| | dashboard | ✔️ | | ✔️ | ✔️ | | | -| | email_templates | ✔️ | | ✔️ | ✔️ | | | -| | filter | | | ✔️ | ✔️ | | | -| | guest | (view missing)| | ✔️ | ✔️ | | | -| | import | ✔️ | | ✔️ | ✔️ | | | -| | layout | | | ✔️ | ✔️ | | | -| | mailer | | | ✔️ | ✔️ | | | -| | sessions | | | ✔️ | ✔️ | | | -| | settings | ✔️ | | ✔️ | ✔️ | | | -| | upload | | | ✔️ | ✔️ | | | -| | welcome | ✔️ | | ✔️ | ✔️ | | | -| invoices | | ✔️ | | ✔️ | ✔️ | | | -| | invoice_groups | ✔️ | | ✔️ | ✔️ | | | -| | tax_rates | ✔️ | | ✔️ | ✔️ | | | -| | peppol | ✔️ | ✔️ | ✔️ | ✔️ | | | -| payments | | ✔️ | | ✔️ | ✔️ | | | -| | payment_methods | ✔️ | | ✔️ | ✔️ | | | -| products | | ✔️ | | ✔️ | ✔️ | | | -| | families | ✔️ | | ✔️ | ✔️ | | | -| | units | ✔️ | | ✔️ | ✔️ | | | -| projects | | ✔️ | | ✔️ | ✔️ | | | -| | tasks | ✔️ | | ✔️ | ✔️ | | | -| quotes | | ✔️ | | ✔️ | ✔️ | | | -| reports | | | | ✔️ | ✔️ | | | -| users | | ✔️ | | ✔️ | ✔️ | | | -| setup | | | | ✔️ | ✔️ | | | +| clients | | | | | | | | +| | user_clients | | | | | | | +| core | | | | | | | | +| | custom_fields | | | | | | | +| | custom_values | | | | | | | +| | dashboard | | | | | | | +| | email_templates | | | | | | | +| | filter | | | | | | | +| | guest | (view missing)| | | | | | +| | import | | | | | | | +| | layout | | | | | | | +| | mailer | | | | | | | +| | sessions | | | | | | | +| | settings | | | | | | | +| | upload | | | | | | | +| | welcome | | | | | | | +| invoices | | | | | | | | +| | invoice_groups | | | | | | | +| | tax_rates | | | | | | | +| | peppol | | | | | | | +| payments | | | | | | | | +| | payment_methods | | | | | | | +| products | | | | | | | | +| | families | | | | | | | +| | units | | | | | | | +| projects | | | | | | | | +| | tasks | | | | | | | +| quotes | | | | | | | | +| reports | | | | | | | | +| users | | | | | | | | +| setup | | | | | | | | --- diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 9f4d25994..1594c3e47 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -10,13 +10,13 @@ Thank you for considering contributing to **InvoicePlane V2** — a Laravel + Fi - **Filament** used for all UI - **Livewire** used for reactive components - **Modular** folder structure only: - - `Modules/{Module}/Filament/Admin/Resources/` - - `Modules/{Module}/Services/` - - `Modules/{Module}/Tests/Feature/` + - `Modules/{Module}/Filament/Admin/Resources/` + - `Modules/{Module}/Services/` + - `Modules/{Module}/Tests/Feature/` - Use: - - `BelongsToCompany` trait for multi-tenancy - - `DTOs` + `Transformers` for all data - - `Services` for all business logic + - `BelongsToCompany` trait for multi-tenancy + - `DTOs` + `Transformers` for all data + - `Services` for all business logic --- @@ -53,8 +53,8 @@ All tests should have: /** * @payload missing: invoice_number * { - * "customer_id": 1, - * "due_date": "2025-06-01" + * "customer_id": 1, + * "due_date": "2025-06-01" * } */ public function it_fails_to_create_invoice_without_required_invoice_number(): void @@ -69,8 +69,6 @@ Pull Requests - Translate if needed - Add tests where you can - - --- Translation @@ -80,8 +78,6 @@ All strings use trans('...') Translations managed via Crowdin: https://translations.invoiceplane.com - - --- Community @@ -91,5 +87,3 @@ Discord: https://discord.gg/PPzD2hTrXt Community Forums: https://community.invoiceplane.com GitHub Issues: https://github.com/InvoicePlane/InvoicePlane-v2/issues - - diff --git a/.github/DOCKER.md b/.github/DOCKER.md index 3343ae435..c8d898b4a 100644 --- a/.github/DOCKER.md +++ b/.github/DOCKER.md @@ -28,7 +28,6 @@ docker compose up -d Visit: http://localhost/ivpl - --- Useful Commands @@ -41,8 +40,6 @@ View logs docker compose logs -f Run artisan docker compose exec app php artisan Rebuild containers docker compose build --no-cache - - --- Services @@ -55,8 +52,6 @@ Mail: MailCatcher (port 1080) Queue: Redis (optional) - - --- Customize Docker @@ -67,8 +62,6 @@ Override PHP version via Dockerfile Add volumes for local persistence if needed - - --- Troubleshooting @@ -79,14 +72,10 @@ Permission issues: Ensure Docker has access to your project folder Missing .env config: Re-run cp .env.example .env and adjust - --- - - --- What's Next? Visit CHECKLIST.md if contributing - diff --git a/.github/EXPORT-REFACTORING.md b/.github/EXPORT-REFACTORING.md index 42cbd389f..32283c46e 100644 --- a/.github/EXPORT-REFACTORING.md +++ b/.github/EXPORT-REFACTORING.md @@ -24,9 +24,9 @@ All modules now have dedicated Filament Exporters located in `Modules/{ModuleNam **Internationalization:** - All notification strings use trans() function - New translation keys in resources/lang/en/ip.php: - - `export_completed` - Success notification - - `export_failed_rows` - Failure notification - - `row` - Pluralizable row/rows + - `export_completed` - Success notification + - `export_failed_rows` - Failure notification + - `row` - Pluralizable row/rows **Expenses Module:** - `ExpenseExporter` - Regular export with 7 columns @@ -148,16 +148,16 @@ For each module (Expenses, Products, Quotes, Projects, Tasks, Relations, Contact 1. Navigate to the list page 2. Click the "Export" button 3. Test each of the 4 export options: - - Export as CSV (v2) - - Export as CSV (v1, Legacy) - - Export as Excel (v2) - - Export as Excel (v1, Legacy) + - Export as CSV (v2) + - Export as CSV (v1, Legacy) + - Export as Excel (v2) + - Export as Excel (v1, Legacy) 4. Verify: - - Modal opens with column selection - - Export completes successfully - - Notification is received - - File downloads correctly - - File contains expected data and columns + - Modal opens with column selection + - Export completes successfully + - Notification is received + - File downloads correctly + - File contains expected data and columns ### Automated Testing diff --git a/.github/IMPORTING.md b/.github/IMPORTING.md index ca3009d31..2694d27d2 100644 --- a/.github/IMPORTING.md +++ b/.github/IMPORTING.md @@ -4,14 +4,14 @@ InvoicePlane supports importing data from external systems using CSV files. This --- -## 📂 Accessing the Import Tool +## Accessing the Import Tool 1. Navigate to **Settings**. 2. Click on **Import Data**. --- -## 📄 Import Requirements +## Import Requirements To ensure a successful import: @@ -26,64 +26,64 @@ To ensure a successful import: --- -## 📁 Supported Files and Structures +## Supported Files and Structures ### 1. `customers.csv` -| Column Name | Description | +| Column Name | Description | |---------------------|-------------------------------------| -| `client_name` | Customer's full name | -| `client_address_1` | Primary address line | -| `client_address_2` | Secondary address line | -| `client_city` | City | -| `client_state` | State or province | -| `client_zip` | ZIP or postal code | -| `client_country` | Country | -| `client_phone` | Phone number | -| `client_fax` | Fax number | -| `client_mobile` | Mobile number | -| `client_email` | Email address | -| `client_web` | Website URL | -| `client_vat_id` | VAT identification number | -| `client_tax_code` | Tax code | -| `client_active` | Status (`1` for active, `0` for inactive) | +| `client_name` | Customer's full name | +| `client_address_1` | Primary address line | +| `client_address_2` | Secondary address line | +| `client_city` | City | +| `client_state` | State or province | +| `client_zip` | ZIP or postal code | +| `client_country` | Country | +| `client_phone` | Phone number | +| `client_fax` | Fax number | +| `client_mobile` | Mobile number | +| `client_email` | Email address | +| `client_web` | Website URL | +| `client_vat_id` | VAT identification number | +| `client_tax_code` | Tax code | +| `client_active` | Status (`1` for active, `0` for inactive) | ### 2. `invoices.csv` -| Column Name | Description | +| Column Name | Description | |-------------------------|-------------------------------------------| -| `user_email` | Email of the InvoicePlane user | -| `client_name` | Name of the customer | -| `invoice_date_created` | Creation date (`YYYY-MM-DD`) | -| `invoice_date_due` | Due date (`YYYY-MM-DD`) | -| `invoice_number` | Unique invoice number | -| `invoice_terms` | Payment terms | +| `user_email` | Email of the InvoicePlane user | +| `client_name` | Name of the customer | +| `invoice_date_created` | Creation date (`YYYY-MM-DD`) | +| `invoice_date_due` | Due date (`YYYY-MM-DD`) | +| `invoice_number` | Unique invoice number | +| `invoice_terms` | Payment terms | ### 3. `invoice_items.csv` -| Column Name | Description | +| Column Name | Description | |--------------------|-------------------------------------------| -| `invoice_number` | Associated invoice number | -| `item_tax_rate` | Tax rate (e.g., `7.8` for 7.8%) | -| `item_date_added` | Date added (`YYYY-MM-DD`) | -| `item_name` | Name of the item | -| `item_description` | Description of the item | -| `item_quantity` | Quantity of the item | -| `item_price` | Price per item (numeric, no currency symbols) | +| `invoice_number` | Associated invoice number | +| `item_tax_rate` | Tax rate (e.g., `7.8` for 7.8%) | +| `item_date_added` | Date added (`YYYY-MM-DD`) | +| `item_name` | Name of the item | +| `item_description` | Description of the item | +| `item_quantity` | Quantity of the item | +| `item_price` | Price per item (numeric, no currency symbols) | ### 4. `payments.csv` -| Column Name | Description | +| Column Name | Description | |------------------|-------------------------------------------| -| `invoice_number` | Associated invoice number | -| `payment_method` | Method of payment (e.g., Cash, Credit) | -| `payment_date` | Date of payment (`YYYY-MM-DD`) | +| `invoice_number` | Associated invoice number | +| `payment_method` | Method of payment (e.g., Cash, Credit) | +| `payment_date` | Date of payment (`YYYY-MM-DD`) | | `payment_amount` | Amount paid (numeric, no currency symbols)| -| `payment_note` | Additional notes | +| `payment_note` | Additional notes | --- -## ⚠️ Important Notes +## Important Notes - **Custom Fields**: Importing custom fields is not supported in the current version. - **Data Validation**: Ensure all data is accurate and conforms to the required formats to prevent import errors. @@ -91,7 +91,7 @@ To ensure a successful import: --- -## 🛠️ Troubleshooting +## Troubleshooting - **Import Errors**: If the import process fails, double-check file formats, headers, and data consistency. - **Community Support**: For assistance, visit the [InvoicePlane Community Forums](https://community.invoiceplane.com/). diff --git a/.github/INSTALLATION.md b/.github/INSTALLATION.md index 9774d14df..38870eaa8 100644 --- a/.github/INSTALLATION.md +++ b/.github/INSTALLATION.md @@ -13,8 +13,6 @@ Requirements - Laravel CLI (php artisan) - Docker, Laravel Herd, or XAMPP/WAMP (or equivalents) - - --- Preparations: @@ -36,7 +34,6 @@ or Visit: http://localhost/ or your own sitename - --- Option 2: Laravel Herd (macOS / Windows) @@ -44,20 +41,16 @@ Option 2: Laravel Herd (macOS / Windows) Visit: `http://invoiceplane.test/` See YouTube video - --- Option 3: XAMPP / WAMP / MAMP 1. Place the project inside your htdocs or www directory. - 2. Create a database (e.g., invoiceplane_db). - 3. Update your .env: - ```bash DB_CONNECTION=mysql DB_DATABASE=invoiceplane_db @@ -67,7 +60,6 @@ DB_PASSWORD= Visit: `http://localhost/invoiceplane` - --- Option 4: PHP Artisan Serve @@ -76,7 +68,6 @@ Option 4: PHP Artisan Serve Visit: `http://127.0.0.1:8000/` - --- ## Shared Setup Steps @@ -99,4 +90,3 @@ Discord: https://discord.gg/PPzD2hTrXt Community Forums: https://community.invoiceplane.com Wiki: https://wiki.invoiceplane.com - diff --git a/.github/MAINTENANCE.md b/.github/MAINTENANCE.md new file mode 100644 index 000000000..5e953c659 --- /dev/null +++ b/.github/MAINTENANCE.md @@ -0,0 +1,352 @@ +# Maintenance Guide for InvoicePlane v2 + +This document provides guidelines for maintaining the InvoicePlane v2 application, including dependency management, security updates, and best practices. + +--- + +## Dependency Management + +### Package Managers + +InvoicePlane v2 uses two package managers: + +- **Composer** - PHP dependencies (backend) +- **Yarn** - JavaScript dependencies (frontend) + +### Lockfiles + +Both package managers use lockfiles to ensure consistent dependency versions: + +- `composer.lock` - Locks PHP dependencies +- `yarn.lock` - Locks JavaScript dependencies + +--- + +## When to Use `--frozen-lockfile` + +### Composer + +Use `composer install --no-interaction --prefer-dist` in the following scenarios: + +- **CI/CD Pipelines** - To ensure reproducible builds +- **Production Deployments** - To install exact versions from lockfile +- **Testing Environments** - To test against known dependency versions + +### Yarn + +Use `yarn install --frozen-lockfile` in the following scenarios: + +- **CI/CD Pipelines** - To ensure consistent builds across environments +- **Production Deployments** - To prevent unexpected dependency changes +- **Team Collaboration** - To ensure all developers use the same versions + +**Example GitHub Actions:** +```yaml +- name: Install Composer dependencies + run: composer install --no-interaction --prefer-dist --optimize-autoloader + +- name: Install Yarn dependencies + run: yarn install --frozen-lockfile +``` + +--- + +## When to "Unfreeze" and Upgrade Packages + +### Regular Maintenance + +Perform dependency updates in the following scenarios: + +1. **Security Updates** - Immediately when security vulnerabilities are discovered +2. **Monthly Updates** - Scheduled maintenance for minor and patch updates +3. **Major Updates** - Quarterly or as needed for major version updates +4. **Feature Requirements** - When new features require updated dependencies + +### How to Upgrade + +#### Composer (PHP Dependencies) + +```bash +# Update all dependencies (respecting version constraints) +composer update + +# Update specific package +composer update vendor/package + +# Update with security fixes only +composer update --with-dependencies + +# Dry run to see what would be updated +composer update --dry-run +``` + +#### Yarn (JavaScript Dependencies) + +```bash +# Update all dependencies (respecting version constraints) +yarn upgrade + +# Update specific package +yarn upgrade package-name + +# Update to latest versions (ignore constraints) +yarn upgrade-interactive --latest + +# Check for outdated packages +yarn outdated +``` + +### Before Upgrading + +1. **Review Changelog** - Read release notes and breaking changes +2. **Backup** - Create a backup or work in a separate branch +3. **Test Locally** - Run full test suite after upgrades +4. **Update Gradually** - Update one package at a time for major versions + +### After Upgrading + +1. **Run Tests** - Execute full test suite to ensure compatibility +2. **Update Code** - Fix any breaking changes or deprecations +3. **Update Documentation** - Document any significant dependency changes +4. **Commit Lockfiles** - Always commit updated lockfiles + +--- + +## Security Alert Response Process + +### When You Receive a Security Alert + +GitHub Dependabot and other tools will notify you of security vulnerabilities. Follow this process to respond quickly and effectively: + +#### 1. **Assess the Alert** + +- **Review the CVE** - Understand the vulnerability and its impact +- **Check Severity** - Critical and High severity alerts require immediate action +- **Determine Scope** - Identify affected parts of the application +- **Check Exploitability** - Is the vulnerability actively exploited? + +#### 2. **Prioritize Response** + +| Severity | Response Time | Action | +|----------|---------------|--------| +| **Critical** | Immediate (within 24 hours) | Emergency patch and deploy | +| **High** | 1-3 days | Patch and deploy quickly | +| **Medium** | 1-2 weeks | Include in next maintenance cycle | +| **Low** | 1 month | Include in monthly update | + +#### 3. **Apply the Fix** + +```bash +# For Composer dependencies +composer update vendor/package --with-dependencies + +# For Yarn dependencies +yarn upgrade package-name + +# Run tests to verify the fix +php artisan test +``` + +#### 4. **Verify the Fix** + +- Run the full test suite +- Test affected functionality manually +- Use security scanning tools to verify the fix: + ```bash + composer audit + yarn audit + ``` + +#### 5. **Deploy** + +- **Critical/High Severity** - Deploy as a hotfix +- **Medium/Low Severity** - Include in regular deployment cycle + +#### 6. **Document** + +- Update `CHANGELOG.md` with security fix details +- Create a security advisory if necessary +- Notify users if the vulnerability affected production + +--- + +## Automated Dependency Scanning + +### GitHub Dependabot + +InvoicePlane v2 uses GitHub Dependabot to automatically detect and create pull requests for security updates. + +**Dependabot Configuration** (`.github/dependabot.yml`): +```yaml +version: 2 +updates: + # Composer + - package-ecosystem: "composer" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 + + # npm/Yarn + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + open-pull-requests-limit: 10 +``` + +### Manual Security Audits + +Run periodic security audits manually: + +```bash +# Composer security audit +composer audit + +# Yarn security audit +yarn audit + +# Fix Yarn vulnerabilities automatically (when possible) +yarn audit --fix +``` + +--- + +## Maintenance Schedule + +### Weekly + +- Review Dependabot pull requests +- Check for critical security alerts +- Monitor error logs for issues + +### Monthly + +- Update dependencies (patch and minor versions) +- Review and merge dependency updates +- Run full test suite +- Update documentation if needed + +### Quarterly + +- Review major version updates +- Plan and test major upgrades +- Update infrastructure dependencies +- Comprehensive security audit + +### Annually + +- Review and update maintenance processes +- Evaluate new tools and practices +- Major refactoring and technical debt reduction + +--- + +## GitHub Actions Workflows + +### Automated Dependency Updates + +InvoicePlane v2 includes GitHub Actions workflows for automated dependency management: + +- **Composer Update Workflow** - `.github/workflows/composer-update.yml` +- **Yarn Update Workflow** - `.github/workflows/yarn-update.yml` + +These workflows can be triggered manually or on a schedule to: +- Update dependencies +- Run tests +- Create pull requests with updates + +See: `.github/workflows/` directory for workflow details. + +--- + +## Tools and Commands + +### Code Quality + +```bash +# Format code +vendor/bin/pint + +# Static analysis +vendor/bin/phpstan analyse + +# Rector (automated refactoring) +vendor/bin/rector process --dry-run +``` + +### Testing + +```bash +# Run all tests +php artisan test + +# Run with coverage +php artisan test --coverage + +# Run specific test suite +php artisan test --testsuite=Unit +``` + +### Database + +```bash +# Fresh migration with seeding +php artisan migrate:fresh --seed + +# Rollback and migrate +php artisan migrate:refresh +``` + +--- + +## Best Practices + +### General + +1. **Always commit lockfiles** - `composer.lock` and `yarn.lock` +2. **Test before deploying** - Run full test suite after updates +3. **Use branches** - Create a branch for dependency updates +4. **Document changes** - Update CHANGELOG.md +5. **Review pull requests** - Don't auto-merge dependency updates + +### Security + +1. **Act quickly on critical alerts** - Prioritize security over features +2. **Subscribe to security mailing lists** - Stay informed about vulnerabilities +3. **Use security headers** - Implement proper security headers in production +4. **Regular backups** - Maintain regular database and file backups + +### Dependencies + +1. **Keep dependencies up to date** - Regular updates reduce security risks +2. **Minimize dependencies** - Only add necessary packages +3. **Review new dependencies** - Check package reputation and maintenance +4. **Use semantic versioning** - Understand version constraints in composer.json/package.json + +--- + +## Additional Resources + +- **Installation Guide** - `.github/INSTALLATION.md` +- **Contributing Guide** - `.github/CONTRIBUTING.md` +- **Security Policy** - `.github/SECURITY.md` +- **Upgrade Guide** - `.github/UPGRADE.md` +- **Composer Documentation** - https://getcomposer.org/doc/ +- **Yarn Documentation** - https://yarnpkg.com/getting-started +- **GitHub Dependabot** - https://docs.github.com/en/code-security/dependabot + +--- + +## Support + +If you encounter issues with dependency management or security updates: + +- **Discord** - https://discord.gg/PPzD2hTrXt +- **Forums** - https://community.invoiceplane.com +- **GitHub Issues** - https://github.com/InvoicePlane/InvoicePlane-v2/issues +- **Security Issues** - See `.github/SECURITY.md` for responsible disclosure + +--- + +**Last Updated:** 2025-12-29 diff --git a/.github/QUICKSTART.md b/.github/QUICKSTART.md index 4d4e332ef..4fa2f2ac3 100644 --- a/.github/QUICKSTART.md +++ b/.github/QUICKSTART.md @@ -13,7 +13,6 @@ php artisan key:generate php artisan migrate --seed ``` - Then visit: `http://localhost:8000/ivpl` (Artisan) diff --git a/.github/SEEDING.md b/.github/SEEDING.md index a0defe268..112c1d90d 100644 --- a/.github/SEEDING.md +++ b/.github/SEEDING.md @@ -29,7 +29,6 @@ To re-seed the database: Note: Never use test seeders in production unless you customize them for live use. - --- Want to add new seed data for a module? diff --git a/.github/SETUP.md b/.github/SETUP.md index 3e388ca2d..e57593dd7 100644 --- a/.github/SETUP.md +++ b/.github/SETUP.md @@ -11,7 +11,6 @@ git clone https://github.com/InvoicePlane/InvoicePlane-v2.git ivplv2 cd ivplv2 ``` - --- 2. Create the Environment File @@ -27,7 +26,6 @@ DB_USERNAME=root DB_PASSWORD=yourpassword ``` - --- 3. Install Dependencies @@ -41,16 +39,12 @@ DB_PASSWORD=yourpassword `php artisan key:generate` - --- 5. Migrate and Seed Database `php artisan migrate --seed` - - - --- Optional Tools @@ -60,4 +54,3 @@ Laravel Herd → https://laravel.com/docs/herd MailCatcher → http://localhost:1080 Docker → See DOCKER.md - diff --git a/.github/THEMES.md b/.github/THEMES.md index 9f78affe5..eceff8a57 100644 --- a/.github/THEMES.md +++ b/.github/THEMES.md @@ -38,9 +38,9 @@ Based on the popular Nord color palette, this theme features cool, arctic-inspir - **Snow Storm** (Text): #eceff4, #e5e9f0 - **Frost** (Accents): #88c0d0, #5e81ac - **Aurora** (Semantic): - - Danger: #bf616a (red) - - Warning: #ebcb8b (yellow) - - Success: #a3be8c (green) + - Danger: #bf616a (red) + - Warning: #ebcb8b (yellow) + - Success: #a3be8c (green) **Best For:** Developers who love the Nord color scheme, or anyone preferring a cool, calming interface @@ -95,12 +95,12 @@ To apply a theme to a Filament panel, update the panel provider file and set the public function panel(Panel $panel): Panel { - return $panel - ->id('company') - ->path('') - ->viteTheme('resources/css/filament/company/nord.css') // Change this line - ->login() - // ... other configuration + return $panel + ->id('company') + ->path('') + ->viteTheme('resources/css/filament/company/nord.css') // Change this line + ->login() + // ... other configuration } ``` @@ -134,53 +134,53 @@ Each theme includes styling for: To create a new custom theme: 1. Create a new CSS file in `resources/css/filament/company/`: - ```bash - touch resources/css/filament/company/my-custom-theme.css - ``` + ```bash + touch resources/css/filament/company/my-custom-theme.css + ``` 2. Copy the content from an existing theme (e.g., `invoiceplane.css`) as a starting point 3. Update the colors and styles to match your desired theme 4. Register the theme in `vite.config.js`: - ```javascript - input: [ - 'resources/css/app.css', - 'resources/js/app.js', - // ... existing themes - 'resources/css/filament/company/my-custom-theme.css' // Add your theme - ], - ``` + ```javascript + input: [ + 'resources/css/app.css', + 'resources/js/app.js', + // ... existing themes + 'resources/css/filament/company/my-custom-theme.css' // Add your theme + ], + ``` 5. Build the assets: - ```bash - npm run build - ``` + ```bash + npm run build + ``` 6. Update your panel provider to use the new theme: - ```php - ->viteTheme('resources/css/filament/company/my-custom-theme.css') - ``` + ```php + ->viteTheme('resources/css/filament/company/my-custom-theme.css') + ``` ## Nord Theme Colors The Nord theme uses the following color palette: - **Polar Night** - Dark backgrounds and UI elements - - `--color-polarnight-800: #2e3440` (Primary dark background) - - `--color-polarnight-700: #3b4252` (Secondary dark background) - + - `--color-polarnight-800: #2e3440` (Primary dark background) + - `--color-polarnight-700: #3b4252` (Secondary dark background) + - **Snow Storm** - Light text and highlights - - `--color-snowstorm-600: #eceff4` (Primary light text) - + - `--color-snowstorm-600: #eceff4` (Primary light text) + - **Frost** - Primary accent colors - - `--color-frost-500: #88c0d0` (Primary accent) - - `--color-frost-700: #5e81ac` (Secondary accent) - + - `--color-frost-500: #88c0d0` (Primary accent) + - `--color-frost-700: #5e81ac` (Secondary accent) + - **Aurora** - Semantic colors - - `--color-aurora-danger: #bf616a` (Error/danger) - - `--color-aurora-warning: #ebcb8b` (Warning) - - `--color-aurora-success: #a3be8c` (Success) + - `--color-aurora-danger: #bf616a` (Error/danger) + - `--color-aurora-warning: #ebcb8b` (Warning) + - `--color-aurora-success: #a3be8c` (Success) ## Notes @@ -195,29 +195,29 @@ To quickly switch themes for a panel, update the `viteTheme()` method in the app **Admin Panel** (`Modules/Core/Providers/AdminPanelProvider.php`): ```php -->viteTheme('resources/css/filament/company/invoiceplane.css') // Default +->viteTheme('resources/css/filament/company/invoiceplane.css') // Default ->viteTheme('resources/css/filament/company/invoiceplane-blue.css') // Blue -->viteTheme('resources/css/filament/company/nord.css') // Nord -->viteTheme('resources/css/filament/company/orange.css') // Orange -->viteTheme('resources/css/filament/company/reddit.css') // Reddit +->viteTheme('resources/css/filament/company/nord.css') // Nord +->viteTheme('resources/css/filament/company/orange.css') // Orange +->viteTheme('resources/css/filament/company/reddit.css') // Reddit ``` **Company Panel** (`Modules/Core/Providers/CompanyPanelProvider.php`): ```php -->viteTheme('resources/css/filament/company/invoiceplane.css') // Default +->viteTheme('resources/css/filament/company/invoiceplane.css') // Default ->viteTheme('resources/css/filament/company/invoiceplane-blue.css') // Blue -->viteTheme('resources/css/filament/company/nord.css') // Nord -->viteTheme('resources/css/filament/company/orange.css') // Orange -->viteTheme('resources/css/filament/company/reddit.css') // Reddit +->viteTheme('resources/css/filament/company/nord.css') // Nord +->viteTheme('resources/css/filament/company/orange.css') // Orange +->viteTheme('resources/css/filament/company/reddit.css') // Reddit ``` **User Panel** (`Modules/Core/Providers/UserPanelProvider.php`): ```php -->viteTheme('resources/css/filament/company/invoiceplane.css') // Default +->viteTheme('resources/css/filament/company/invoiceplane.css') // Default ->viteTheme('resources/css/filament/company/invoiceplane-blue.css') // Blue -->viteTheme('resources/css/filament/company/nord.css') // Nord -->viteTheme('resources/css/filament/company/orange.css') // Orange -->viteTheme('resources/css/filament/company/reddit.css') // Reddit +->viteTheme('resources/css/filament/company/nord.css') // Nord +->viteTheme('resources/css/filament/company/orange.css') // Orange +->viteTheme('resources/css/filament/company/reddit.css') // Reddit ``` After changing the theme, rebuild assets: diff --git a/.github/TRANSLATIONS.md b/.github/TRANSLATIONS.md index 5719b2d12..94a665932 100644 --- a/.github/TRANSLATIONS.md +++ b/.github/TRANSLATIONS.md @@ -4,14 +4,14 @@ InvoicePlane is a multilingual application, and we rely on community contributio --- -## 🌍 Where Are Translations Managed? +## Where Are Translations Managed? -All translations are hosted on **[Crowdin](https://crowdin.com/)** under the project name: +All translations are hosted on **[Crowdin](https://crowdin.com/)** under the project name: **[InvoicePlane on Crowdin](https://translations.invoiceplane.com)** --- -## 🔹 How to Contribute +## How to Contribute 1. Create an account at [crowdin.com](https://crowdin.com/). 2. Join the **InvoicePlane** project via [translations.invoiceplane.com](https://translations.invoiceplane.com). @@ -21,7 +21,7 @@ All translations are hosted on **[Crowdin](https://crowdin.com/)** under the pro --- -## 📜 Translation Guidelines +## Translation Guidelines - Use consistent terminology (reference existing translations). - **Do not translate** variables like `{invoice_number}` or `{client_name}`. @@ -30,7 +30,7 @@ All translations are hosted on **[Crowdin](https://crowdin.com/)** under the pro --- -## 🛠️ Technical Details (for Developers) +## Technical Details (for Developers) - Translations are stored in `lang/{locale}/` using Laravel conventions. - File format is PHP: `lang/en/invoices.php`, `lang/fr/clients.php`, etc. @@ -39,7 +39,7 @@ All translations are hosted on **[Crowdin](https://crowdin.com/)** under the pro --- -## 💬 Need Help? +## Need Help? - Ask questions in our [Community Forums](https://community.invoiceplane.com). - Reach out via [Discord](https://discord.gg/PPzD2hTrXt). diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 0d45947e3..3714c41e0 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -8,9 +8,9 @@ This project is **InvoicePlane v2**, a **multi-tenant Laravel application** with - The application uses **Laravel Filament** for Admin Panel, Company Panel, and InvoicePanel interfaces. - Code is structured into **Modules**, each module encapsulating its own logic (models, services, repositories, DTOs, - transformers, tests, etc.). -- Tests for each module are located in: - `/Modules/(ModuleName)/Tests` + transformers, tests, etc.). +- Tests for each module are located in: + `/Modules/(ModuleName)/Tests` ## Tech Stack @@ -112,28 +112,28 @@ php artisan queue:work - **Filament resources must respect proper panel separation and namespaces.** - **Resource Generation (via commands):** - - Must use Filament internal traits (`CanReadModelSchemas`, etc.). - - No reflection for relationship detection. - - Separate form and table generators by field type. - - Keep a configurable `$excludedFields` array. - - Enums detected via `$casts` and `enum_exists()`. - - Add docblocks above `form()`, `table()`, `getRelations()` with relationships/fields. - - Use `copyStubToApp()` instead of inline string replacements. - - **Preserve the exact method signatures** for Filament resource methods. - - **Use the correct `Action::make()` syntax** with fluent methods. - - **Do not display raw `created_at` or `updated_at`** in tables/infolists; use dedicated timestamp columns. + - Must use Filament internal traits (`CanReadModelSchemas`, etc.). + - No reflection for relationship detection. + - Separate form and table generators by field type. + - Keep a configurable `$excludedFields` array. + - Enums detected via `$casts` and `enum_exists()`. + - Add docblocks above `form()`, `table()`, `getRelations()` with relationships/fields. + - Use `copyStubToApp()` instead of inline string replacements. + - **Preserve the exact method signatures** for Filament resource methods. + - **Use the correct `Action::make()` syntax** with fluent methods. + - **Do not display raw `created_at` or `updated_at`** in tables/infolists; use dedicated timestamp columns. ### Testing Rules - **Unit Tests must follow these rules:** - - Test functions must be prefixed with `it_` and make grammatical sense (e.g., `it_creates_payment`, `it_validates_invoice_has_customer`). - - Use `#[Test]` attribute instead of `@test` annotations. - - Prefer Fakes and Fixtures over Mocks. - - Place happy paths last in test cases. - - Reusable logic (e.g., fixtures, setup) must live in abstract test cases, not inline. - - Tests have inline comment blocks above sections (/* Arrange */, /* Act */, /* Assert */). - - Tests must be meaningful - avoid simple "ok" checks; validate actual behavior and data. - - Use data providers for testing multiple scenarios with the same logic. + - Test functions must be prefixed with `it_` and make grammatical sense (e.g., `it_creates_payment`, `it_validates_invoice_has_customer`). + - Use `#[Test]` attribute instead of `@test` annotations. + - Prefer Fakes and Fixtures over Mocks. + - Place happy paths last in test cases. + - Reusable logic (e.g., fixtures, setup) must live in abstract test cases, not inline. + - Tests have inline comment blocks above sections (/* Arrange */, /* Act */, /* Assert */). + - Tests must be meaningful - avoid simple "ok" checks; validate actual behavior and data. + - Use data providers for testing multiple scenarios with the same logic. ### Export System Rules diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..289b50495 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,82 @@ +version: 2 +updates: + # Composer - PHP dependencies + - package-ecosystem: "composer" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "09:00" + timezone: "UTC" + open-pull-requests-limit: 10 + labels: + - "dependencies" + - "composer" + - "automated-pr" + commit-message: + prefix: "chore(deps)" + include: "scope" + reviewers: + - "nielsdrost7" + # Group updates by dependency type + groups: + security-updates: + patterns: + - "*" + update-types: + - "security" + patch-updates: + patterns: + - "*" + update-types: + - "patch" + + # npm/Yarn - JavaScript dependencies + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "10:00" + timezone: "UTC" + open-pull-requests-limit: 10 + labels: + - "dependencies" + - "yarn" + - "automated-pr" + commit-message: + prefix: "chore(deps)" + include: "scope" + reviewers: + - "nielsdrost7" + # Group updates by dependency type + groups: + security-updates: + patterns: + - "*" + update-types: + - "security" + patch-updates: + patterns: + - "*" + update-types: + - "patch" + + # GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + day: "monday" + time: "11:00" + timezone: "UTC" + open-pull-requests-limit: 5 + labels: + - "dependencies" + - "github-actions" + - "automated-pr" + commit-message: + prefix: "chore(deps)" + include: "scope" + reviewers: + - "nielsdrost7" diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 41344e9cb..28f3bd84b 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -75,36 +75,118 @@ After the workflow runs: Artifacts are also available in the Actions tab for 90 days. -### 2. PHPUnit Tests (`phpunit.yml`) +### 2. Composer Dependency Update (`composer-update.yml`) + +**Trigger:** +- Scheduled: Weekly on Mondays at 9:00 AM UTC +- Manual dispatch with update type selection + +**Purpose:** Automates Composer (PHP) dependency updates with security checks + +**What it does:** +1. **Runs security audit** - Checks for known vulnerabilities +2. **Updates dependencies** - Based on selected update type +3. **Runs tests** - Executes unit tests to verify compatibility +4. **Runs static analysis** - PHPStan checks for type errors +5. **Creates pull request** - Automated PR with update details + +**Update Types:** +- `security-only` - Only security fixes (default for scheduled runs) +- `patch-minor` - Patch and minor version updates +- `all-dependencies` - All updates including major versions + +**Required Permissions:** +- `contents: write` - For creating branches and commits +- `pull-requests: write` - For creating pull requests + +### 3. Yarn Dependency Update (`yarn-update.yml`) + +**Trigger:** +- Scheduled: Weekly on Mondays at 10:00 AM UTC +- Manual dispatch with update type selection + +**Purpose:** Automates Yarn (JavaScript) dependency updates with security checks + +**What it does:** +1. **Runs security audit** - Checks for known vulnerabilities +2. **Updates dependencies** - Based on selected update type +3. **Builds assets** - Verifies frontend builds correctly +4. **Creates pull request** - Automated PR with update details + +**Update Types:** +- `security-only` - Only security fixes (default for scheduled runs) +- `patch-minor` - Patch and minor version updates +- `all-dependencies` - All updates including major versions + +**Required Permissions:** +- `contents: write` - For creating branches and commits +- `pull-requests: write` - For creating pull requests + +### 4. PHPUnit Tests (`phpunit.yml`) **Trigger:** Manual dispatch only Runs the PHPUnit test suite against a MySQL database. -### 3. Laravel Pint (`pint.yml`) +### 5. Laravel Pint (`pint.yml`) **Trigger:** Manual dispatch only Runs Laravel Pint for code formatting checks. -### 4. PHPStan (`phpstan.yml`) +### 6. PHPStan (`phpstan.yml`) **Trigger:** Manual dispatch only Runs PHPStan static analysis. -### 5. Docker Compose Check (`docker.yml`) +### 7. Docker Compose Check (`docker.yml`) **Trigger:** Manual dispatch only Tests Docker Compose configuration. -### 6. Quickstart (`quickstart.yml`) +### 8. Quickstart (`quickstart.yml`) **Trigger:** Manual dispatch only Provides a quick setup for development environments. +## Dependency Management + +### GitHub Dependabot + +InvoicePlane v2 uses GitHub Dependabot for automated dependency updates. Configuration is in `.github/dependabot.yml`. + +**What Dependabot monitors:** +- Composer (PHP dependencies) - Weekly updates on Mondays +- npm/Yarn (JavaScript dependencies) - Weekly updates on Mondays +- GitHub Actions - Monthly updates + +**How it works:** +1. Dependabot scans for outdated or vulnerable dependencies +2. Creates pull requests for updates +3. Groups updates by type (security, patch, minor) +4. Automatically labels PRs for easy filtering + +**Managing Dependabot PRs:** +- Review the changelog and breaking changes +- Run tests locally if needed +- Merge when ready or close if not needed +- Use `@dependabot rebase` to rebase the PR + +See [MAINTENANCE.md](../MAINTENANCE.md) for detailed dependency management guidelines. + +### Manual Dependency Updates + +Use the manual workflows when you need immediate updates: + +1. Go to **Actions** tab +2. Select **Composer Update** or **Yarn Update** +3. Click **Run workflow** +4. Select update type +5. Wait for automated PR + ## Workflow Optimization ### Vendor Directory Cleanup @@ -161,21 +243,21 @@ If Composer installation fails: Edit line 49 in `release.yml`: ```yaml -php-version: '8.3' # Using 8.3 for latest features; composer.json requires ^8.2 +php-version: '8.3' # Using 8.3 for latest features; composer.json requires ^8.2 ``` ### Changing Node.js Version Edit line 36 in `release.yml`: ```yaml -node-version: '20' # Change to your desired version +node-version: '20' # Change to your desired version ``` ### Adjusting Artifact Retention Edit line 121 in `release.yml`: ```yaml -retention-days: 90 # Change to your desired retention period (1-90 days) +retention-days: 90 # Change to your desired retention period (1-90 days) ``` ### Custom ZIP Exclusions diff --git a/.github/workflows/composer-update.yml b/.github/workflows/composer-update.yml new file mode 100644 index 000000000..206baad2d --- /dev/null +++ b/.github/workflows/composer-update.yml @@ -0,0 +1,165 @@ +name: Composer Dependency Update + +on: + workflow_dispatch: + inputs: + update_type: + description: 'Type of update to perform' + required: true + type: choice + options: + - security-patch + - patch-minor + - all-dependencies + default: 'security-patch' + schedule: + # Run weekly on Monday at 9:00 AM UTC + - cron: '0 9 * * 1' + +permissions: + contents: write + pull-requests: write + +jobs: + update-composer-dependencies: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + extensions: mbstring, xml, ctype, json, fileinfo, pdo, sqlite, mysql + coverage: none + + - name: Get Composer Cache Directory + id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache Composer dependencies + uses: actions/cache@v4 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install Composer dependencies + run: composer install --no-interaction --prefer-dist --optimize-autoloader + + - name: Run Composer audit + id: audit + run: | + composer audit --format=json > audit-report.json || true + if [ -s audit-report.json ]; then + echo "vulnerabilities_found=true" >> $GITHUB_OUTPUT + else + echo "vulnerabilities_found=false" >> $GITHUB_OUTPUT + fi + + - name: Update Composer dependencies (Security & Patch Updates) + if: github.event.inputs.update_type == 'security-patch' || github.event_name == 'schedule' + run: | + # Note: This updates all dependencies while respecting version constraints in composer.json + # For true security-only updates, manually update specific vulnerable packages + composer update --with-dependencies --prefer-stable --no-interaction + + - name: Update Composer dependencies (Patch & Minor) + if: github.event.inputs.update_type == 'patch-minor' + run: | + composer update --prefer-stable --no-interaction + + - name: Update Composer dependencies (All) + if: github.event.inputs.update_type == 'all-dependencies' + run: | + composer update --prefer-stable --no-interaction + + - name: Run tests + run: | + cp .env.example .env + php artisan key:generate + php artisan test --testsuite=Unit + + - name: Run static analysis + run: vendor/bin/phpstan analyse --no-progress --error-format=github || true + + - name: Run code formatting + run: vendor/bin/pint --test || true + + - name: Check for changes + id: check-changes + run: | + if git diff --quiet composer.lock; then + echo "changes_detected=false" >> $GITHUB_OUTPUT + else + echo "changes_detected=true" >> $GITHUB_OUTPUT + fi + + - name: Get updated packages + if: steps.check-changes.outputs.changes_detected == 'true' + id: updated-packages + run: | + # Get list of updated packages + git diff composer.lock | grep -E '^\+.*"(name|version)"' | head -20 > updated-packages.txt || echo "Multiple packages updated" > updated-packages.txt + echo "UPDATED_PACKAGES<> $GITHUB_OUTPUT + cat updated-packages.txt >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Create Pull Request + if: steps.check-changes.outputs.changes_detected == 'true' + uses: peter-evans/create-pull-request@v6 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore(deps): update Composer dependencies (${{ github.event.inputs.update_type || 'security-patch' }})" + branch: automated/composer-update-${{ github.run_number }} + delete-branch: true + title: "chore(deps): Update Composer dependencies (${{ github.event.inputs.update_type || 'security-patch' }})" + body: | + ## Composer Dependency Update + + This PR updates Composer dependencies. + + **Update Type:** ${{ github.event.inputs.update_type }} + **Triggered by:** ${{ github.event_name }} + + ### Updated Packages + + ``` + ${{ steps.updated-packages.outputs.UPDATED_PACKAGES }} + ``` + + ### Checks Performed + + - [x] Unit tests passed + - [x] Static analysis completed + - [x] Code formatting checked + + ### Security Audit + + ${{ steps.audit.outputs.vulnerabilities_found == 'true' && 'Security vulnerabilities detected. Please review audit-report.json.' || 'No security vulnerabilities detected.' }} + + ### Review Checklist + + - [ ] Review updated packages and their changelogs + - [ ] Verify all tests pass + - [ ] Check for breaking changes + - [ ] Update documentation if needed + - [ ] Test manually in development environment + + --- + + *This PR was automatically created by the Composer Update workflow.* + labels: | + dependencies + composer + automated-pr + reviewers: | + ${{ github.repository_owner }} + + - name: No changes detected + if: steps.check-changes.outputs.changes_detected == 'false' + run: echo "No Composer dependency updates available." diff --git a/.github/workflows/pint.yml b/.github/workflows/pint.yml index a05b54d47..526fc986a 100644 --- a/.github/workflows/pint.yml +++ b/.github/workflows/pint.yml @@ -41,7 +41,7 @@ jobs: # Check if there were parse errors if grep -q "Parse error" pint_output.log || grep -q "!" pint_output.log; then echo "parse_errors=true" >> $GITHUB_OUTPUT - echo "⚠️ Parse errors detected in one or more files" + echo "WARNING: Parse errors detected in one or more files" else echo "parse_errors=false" >> $GITHUB_OUTPUT fi @@ -71,10 +71,10 @@ jobs: git push if [[ "${{ steps.pint_run.outputs.parse_errors }}" == "true" ]]; then - echo "⚠️ Changes committed successfully, but some files had parse errors and were not formatted" + echo "WARNING: Changes committed successfully, but some files had parse errors and were not formatted" echo "Please fix the parse errors in the files marked with '!' in the Pint output above" else - echo "✓ All changes committed and pushed successfully" + echo "SUCCESS: All changes committed and pushed successfully" fi - name: Report Parse Errors diff --git a/.github/workflows/yarn-update.yml b/.github/workflows/yarn-update.yml new file mode 100644 index 000000000..e11adfdf8 --- /dev/null +++ b/.github/workflows/yarn-update.yml @@ -0,0 +1,151 @@ +name: Yarn Dependency Update + +on: + workflow_dispatch: + inputs: + update_type: + description: 'Type of update to perform' + required: true + type: choice + options: + - common-packages + - patch-minor + - all-dependencies + default: 'common-packages' + schedule: + # Run weekly on Monday at 10:00 AM UTC + - cron: '0 10 * * 1' + +permissions: + contents: write + pull-requests: write + +jobs: + update-yarn-dependencies: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'yarn' + + - name: Install Yarn dependencies + run: yarn install --frozen-lockfile + + - name: Run Yarn audit + id: audit + continue-on-error: true + run: | + yarn audit --json > audit-report.json || true + if [ -s audit-report.json ]; then + VULNERABILITIES=$(grep -c "auditAdvisory" audit-report.json || echo "0") + if [ "$VULNERABILITIES" -gt 0 ]; then + echo "vulnerabilities_found=true" >> $GITHUB_OUTPUT + echo "vulnerability_count=$VULNERABILITIES" >> $GITHUB_OUTPUT + else + echo "vulnerabilities_found=false" >> $GITHUB_OUTPUT + fi + else + echo "vulnerabilities_found=false" >> $GITHUB_OUTPUT + fi + + - name: Update Yarn dependencies (Common Packages) + if: github.event.inputs.update_type == 'common-packages' || github.event_name == 'schedule' + run: | + # Note: This upgrades a predefined set of commonly updated packages + # For true security-only updates, use yarn audit to identify vulnerable packages + yarn upgrade --pattern 'vite|laravel-vite-plugin|tailwindcss|autoprefixer|axios' + + - name: Update Yarn dependencies (Patch & Minor) + if: github.event.inputs.update_type == 'patch-minor' + run: | + yarn upgrade + + - name: Update Yarn dependencies (All) + if: github.event.inputs.update_type == 'all-dependencies' + run: | + yarn upgrade --latest + + - name: Build assets + run: | + yarn build + + - name: Check for changes + id: check-changes + run: | + if git diff --quiet yarn.lock; then + echo "changes_detected=false" >> $GITHUB_OUTPUT + else + echo "changes_detected=true" >> $GITHUB_OUTPUT + fi + + - name: Get updated packages + if: steps.check-changes.outputs.changes_detected == 'true' + id: updated-packages + run: | + # Get list of updated packages + git diff yarn.lock | grep -E '^\+ ' | grep -v '^\+ version' | head -20 > updated-packages.txt || echo "Multiple packages updated" > updated-packages.txt + echo "UPDATED_PACKAGES<> $GITHUB_OUTPUT + cat updated-packages.txt >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Create Pull Request + if: steps.check-changes.outputs.changes_detected == 'true' + uses: peter-evans/create-pull-request@v6 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore(deps): update Yarn dependencies (${{ github.event.inputs.update_type || 'common-packages' }})" + branch: automated/yarn-update-${{ github.run_number }} + delete-branch: true + title: "chore(deps): Update Yarn dependencies (${{ github.event.inputs.update_type || 'common-packages' }})" + body: | + ## Yarn Dependency Update + + This PR updates Yarn (npm) dependencies. + + **Update Type:** ${{ github.event.inputs.update_type }} + **Triggered by:** ${{ github.event_name }} + + ### Updated Packages + + ``` + ${{ steps.updated-packages.outputs.UPDATED_PACKAGES }} + ``` + + ### Checks Performed + + - [x] Assets built successfully + - [x] Dependencies installed and verified + + ### Security Audit + + ${{ steps.audit.outputs.vulnerabilities_found == 'true' && format('{0} security vulnerabilities detected. Please review audit-report.json.', steps.audit.outputs.vulnerability_count) || 'No security vulnerabilities detected.' }} + + ### Review Checklist + + - [ ] Review updated packages and their changelogs + - [ ] Verify assets build correctly + - [ ] Check for breaking changes in frontend + - [ ] Test UI changes in development environment + - [ ] Verify no console errors in browser + + --- + + *This PR was automatically created by the Yarn Update workflow.* + labels: | + dependencies + yarn + automated-pr + reviewers: | + ${{ github.repository_owner }} + + - name: No changes detected + if: steps.check-changes.outputs.changes_detected == 'false' + run: echo "No Yarn dependency updates available." diff --git a/.junie/guidelines.md b/.junie/guidelines.md index 6741b6a3d..3fc02b98b 100644 --- a/.junie/guidelines.md +++ b/.junie/guidelines.md @@ -4,7 +4,7 @@ This document provides comprehensive guidelines for AI agents (like Junie) worki --- -## 🎯 Project Overview +## Project Overview **InvoicePlane v2** is a multi-tenant invoicing and billing application built with modern PHP/Laravel technologies. @@ -20,20 +20,20 @@ This document provides comprehensive guidelines for AI agents (like Junie) worki ### Module Structure ``` Modules/ -├── ModuleName/ -│ ├── Models/ # Eloquent models -│ ├── Services/ # Business logic layer -│ ├── Repositories/ # Data access layer -│ ├── DTOs/ # Data Transfer Objects -│ ├── Transformers/ # DTO ↔ Model transformations -│ ├── Filament/ # Filament resources (Admin/Company panels) -│ ├── Tests/ # PHPUnit tests -│ └── Database/ # Migrations, seeders, factories + ModuleName/ + Models/ # Eloquent models + Services/ # Business logic layer + Repositories/ # Data access layer + DTOs/ # Data Transfer Objects + Transformers/ # DTO ↔ Model transformations + Filament/ # Filament resources (Admin/Company panels) + Tests/ # PHPUnit tests + Database/ # Migrations, seeders, factories ``` --- -## 📋 Critical Principles (MUST FOLLOW) +## Critical Principles (MUST FOLLOW) ### 1. SOLID Principles - **Single Responsibility:** Each class has one clear purpose @@ -53,27 +53,27 @@ Modules/ ```php // Catch specific exceptions separately try { - // code + // code } catch (Error $e) { - // Handle Error + // Handle Error } catch (ErrorException $e) { - // Handle ErrorException + // Handle ErrorException } catch (Throwable $e) { - // Handle other throwables + // Handle other throwables } ``` --- -## 🏗️ Architecture Patterns +## Architecture Patterns ### DTO & Transformer Rules **DTOs (Data Transfer Objects):** -- ❌ NO constructors in DTOs -- ✅ Use static named constructors when necessary -- ✅ Rely on getters and setters for data access -- ✅ DTOs are transformed using Transformers +- NO constructors in DTOs +- Use static named constructors when necessary +- Rely on getters and setters for data access +- DTOs are transformed using Transformers **Transformers:** - Must implement `toDto()` and `toModel()` methods @@ -85,41 +85,41 @@ try { // DTO class InvoiceDTO { - private string $number; - private float $total; - - // No constructor! - - public static function fromArray(array $data): self - { - $dto = new self(); - $dto->setNumber($data['number']); - $dto->setTotal($data['total']); - return $dto; - } - - public function getNumber(): string { return $this->number; } - public function setNumber(string $number): void { $this->number = $number; } + private string $number; + private float $total; + + // No constructor! + + public static function fromArray(array $data): self + { + $dto = new self(); + $dto->setNumber($data['number']); + $dto->setTotal($data['total']); + return $dto; + } + + public function getNumber(): string { return $this->number; } + public function setNumber(string $number): void { $this->number = $number; } } // Transformer class InvoiceTransformer { - public function toDto(Invoice $model): InvoiceDTO - { - return InvoiceDTO::fromArray([ - 'number' => $model->number, - 'total' => $model->total, - ]); - } - - public function toModel(InvoiceDTO $dto): Invoice - { - $model = new Invoice(); - $model->number = $dto->getNumber(); - $model->total = $dto->getTotal(); - return $model; - } + public function toDto(Invoice $model): InvoiceDTO + { + return InvoiceDTO::fromArray([ + 'number' => $model->number, + 'total' => $model->total, + ]); + } + + public function toModel(InvoiceDTO $dto): Invoice + { + $model = new Invoice(); + $model->number = $dto->getNumber(); + $model->total = $dto->getTotal(); + return $model; + } } ``` @@ -143,7 +143,7 @@ class InvoiceTransformer --- -## 🧪 Testing Standards +## Testing Standards ### Test Structure ```php @@ -152,22 +152,22 @@ use PHPUnit\Framework\Attributes\Group; class InvoiceServiceTest extends AbstractCompanyPanelTestCase { - use RefreshDatabase; - - #[Test] - #[Group('invoices')] - public function it_creates_invoice_with_valid_data(): void - { - /* Arrange */ - $data = ['number' => 'INV-001', 'total' => 100.00]; - - /* Act */ - $result = $this->service->createInvoice($data); - - /* Assert */ - $this->assertInstanceOf(InvoiceDTO::class, $result); - $this->assertEquals('INV-001', $result->getNumber()); - } + use RefreshDatabase; + + #[Test] + #[Group('invoices')] + public function it_creates_invoice_with_valid_data(): void + { + /* Arrange */ + $data = ['number' => 'INV-001', 'total' => 100.00]; + + /* Act */ + $result = $this->service->createInvoice($data); + + /* Assert */ + $this->assertInstanceOf(InvoiceDTO::class, $result); + $this->assertEquals('INV-001', $result->getNumber()); + } } ``` @@ -175,11 +175,11 @@ class InvoiceServiceTest extends AbstractCompanyPanelTestCase 1. **Test Naming:** Functions prefixed with `it_` (e.g., `it_creates_invoice`) 2. **No `@test` Annotations:** Use `#[Test]` attribute instead 3. **Prefer Fakes over Mocks:** - ```php - Queue::fake(); - Storage::fake('local'); - Notification::fake(); - ``` + ```php + Queue::fake(); + Storage::fake('local'); + Notification::fake(); + ``` 4. **Happy Paths Last:** Place success scenarios at the end 5. **Reusable Setup:** Abstract test cases for fixtures, not inline 6. **Comment Blocks:** Use `/* Arrange */`, `/* Act */`, `/* Assert */` @@ -190,59 +190,59 @@ class InvoiceServiceTest extends AbstractCompanyPanelTestCase #[Group('export')] public function it_dispatches_csv_export_job(): void { - /* Arrange */ - Queue::fake(); - Storage::fake('local'); - $records = Model::factory()->count(3)->create(); - - /* Act */ - Livewire::actingAs($this->user) - ->test(ListPage::class) - ->callAction('exportCsv', data: [ - 'columnMap' => [ - 'field' => ['isEnabled' => true, 'label' => 'Label'], - ], - ]); - - /* Assert */ - Bus::assertChained([ - fn($batch) => $batch instanceof \Illuminate\Bus\PendingBatch - ]); + /* Arrange */ + Queue::fake(); + Storage::fake('local'); + $records = Model::factory()->count(3)->create(); + + /* Act */ + Livewire::actingAs($this->user) + ->test(ListPage::class) + ->callAction('exportCsv', data: [ + 'columnMap' => [ + 'field' => ['isEnabled' => true, 'label' => 'Label'], + ], + ]); + + /* Assert */ + Bus::assertChained([ + fn($batch) => $batch instanceof \Illuminate\Bus\PendingBatch + ]); } ``` --- -## 🗄️ Database & Models +## Database & Models ### Migration Rules -- ❌ NO JSON columns in migrations -- ❌ NO ENUM columns in migrations -- ❌ NO `timestamps()` unless explicitly specified -- ❌ NO `softDeletes()` unless explicitly specified +- NO JSON columns in migrations +- NO ENUM columns in migrations +- NO `timestamps()` unless explicitly specified +- NO `softDeletes()` unless explicitly specified ### Model Rules -- ❌ NO `$fillable` array in models -- ❌ NO `timestamps` or `softDeletes` properties unless needed -- ✅ Use native PHP type hints -- ✅ Use `$casts` for Enum fields +- NO `$fillable` array in models +- NO `timestamps` or `softDeletes` properties unless needed +- Use native PHP type hints +- Use `$casts` for Enum fields ```php class Invoice extends Model { - // No $fillable! - - protected $casts = [ - 'status' => InvoiceStatus::class, // Enum - 'total' => 'decimal:2', - 'issued_at' => 'datetime', - ]; + // No $fillable! + + protected $casts = [ + 'status' => InvoiceStatus::class, // Enum + 'total' => 'decimal:2', + 'issued_at' => 'datetime', + ]; } ``` --- -## 🎨 Filament Resources +## Filament Resources ### Resource Generation - Must use Filament internal traits (`CanReadModelSchemas`, etc.) @@ -265,7 +265,7 @@ class Invoice extends Model --- -## 📤 Export System +## Export System ### Architecture - Exports use Filament's asynchronous export system @@ -303,7 +303,7 @@ command=php /path/to/artisan queue:work --sleep=3 --tries=3 --- -## 🌍 Peppol E-Invoicing Integration +## Peppol E-Invoicing Integration ### Architecture Overview InvoicePlane v2 includes a comprehensive Peppol integration for sending electronic invoices across the European Peppol network. @@ -360,26 +360,26 @@ $service->sendInvoice($invoice, $integration); #[Test] public function it_sends_invoice_to_peppol_successfully(): void { - /* Arrange */ - Http::fake(['https://api.e-invoice.be/*' => Http::response([ - 'document_id' => 'DOC-123456', - 'status' => 'submitted', - ], 200)]); - - $invoice = $this->createMockInvoice(); - - /* Act */ - $result = $this->service->sendInvoiceToPeppol($invoice); - - /* Assert */ - $this->assertTrue($result['success']); - $this->assertEquals('DOC-123456', $result['document_id']); + /* Arrange */ + Http::fake(['https://api.e-invoice.be/*' => Http::response([ + 'document_id' => 'DOC-123456', + 'status' => 'submitted', + ], 200)]); + + $invoice = $this->createMockInvoice(); + + /* Act */ + $result = $this->service->sendInvoiceToPeppol($invoice); + + /* Assert */ + $this->assertTrue($result['success']); + $this->assertEquals('DOC-123456', $result['document_id']); } ``` --- -## 🔐 Security & Permissions +## Security & Permissions ### Seeding Rules - Seed 5 default roles: `superadmin`, `admin`, `assistance`, `useradmin`, `user` @@ -393,22 +393,22 @@ public function it_sends_invoice_to_peppol_successfully(): void --- -## 🛠️ Development Workflow +## Development Workflow ### Commands **Testing:** ```bash -php artisan test # All tests -php artisan test --coverage # With coverage -php artisan test --testsuite=Unit # Unit tests only -php artisan test --group=export # Export tests only +php artisan test # All tests +php artisan test --coverage # With coverage +php artisan test --testsuite=Unit # Unit tests only +php artisan test --group=export # Export tests only ``` **Code Quality:** ```bash -vendor/bin/pint # Format code (PSR-12) -vendor/bin/phpstan analyse # Static analysis +vendor/bin/pint # Format code (PSR-12) +vendor/bin/phpstan analyse # Static analysis vendor/bin/rector process --dry-run # Refactoring suggestions ``` @@ -418,7 +418,7 @@ composer install cp .env.example .env php artisan key:generate php artisan migrate --seed -php artisan queue:work # For exports +php artisan queue:work # For exports ``` ### Git Commit Conventions @@ -428,7 +428,7 @@ php artisan queue:work # For exports --- -## 📚 Documentation References +## Documentation References ### Key Documentation Files - **Installation:** `.github/INSTALLATION.md` @@ -447,7 +447,7 @@ php artisan queue:work # For exports --- -## ⚡ Performance Optimization +## Performance Optimization ### Query Optimization - Use eager loading to prevent N+1 queries @@ -467,22 +467,22 @@ php artisan queue:work # For exports --- -## 🚫 Common Pitfalls to Avoid +## Common Pitfalls to Avoid -1. ❌ Don't use `$fillable` in models -2. ❌ Don't create DTOs with constructors -3. ❌ Don't build DTOs manually in services—use Transformers -4. ❌ Don't use JSON or ENUM columns in migrations -5. ❌ Don't add timestamps/softDeletes unless specified -6. ❌ Don't test export file content—test job dispatching -7. ❌ Don't make direct API calls—use Advanced API Client -8. ❌ Don't use `updateOrCreate`—use repository upsert methods -9. ❌ Don't nest conditions deeply—use early returns -10. ❌ Don't duplicate logic—centralize in traits +1. Don't use `$fillable` in models +2. Don't create DTOs with constructors +3. Don't build DTOs manually in services—use Transformers +4. Don't use JSON or ENUM columns in migrations +5. Don't add timestamps/softDeletes unless specified +6. Don't test export file content—test job dispatching +7. Don't make direct API calls—use Advanced API Client +8. Don't use `updateOrCreate`—use repository upsert methods +9. Don't nest conditions deeply—use early returns +10. Don't duplicate logic—centralize in traits --- -## ✅ Code Review Checklist +## Code Review Checklist Before submitting code, verify: @@ -505,7 +505,7 @@ Before submitting code, verify: --- -## 🎓 Learning Resources +## Learning Resources ### InvoicePlane-Specific - Review existing modules for patterns @@ -524,7 +524,7 @@ Before submitting code, verify: --- -## 🔄 Continuous Improvement +## Continuous Improvement This document should be updated as: - New patterns emerge @@ -536,7 +536,7 @@ This document should be updated as: --- -## 📞 Support +## Support - **Discord:** https://discord.gg/PPzD2hTrXt - **Forums:** https://community.invoiceplane.com diff --git a/Modules/Clients/Enums/Gender.php b/Modules/Clients/Enums/Gender.php index 357ed5c7b..8021cdfe1 100644 --- a/Modules/Clients/Enums/Gender.php +++ b/Modules/Clients/Enums/Gender.php @@ -19,10 +19,10 @@ public static function values(): array public function label(): string { return match ($this) { - self::MALE => 'Male', - self::FEMALE => 'Female', - self::OTHER => 'Other', - self::UNKNOWN => 'Unknown', + self::MALE => trans('ip.gender_male'), + self::FEMALE => trans('ip.gender_female'), + self::OTHER => trans('ip.gender_other'), + self::UNKNOWN => trans('ip.gender_other'), }; } diff --git a/Modules/Clients/Enums/RelationType.php b/Modules/Clients/Enums/RelationType.php index 544176389..81183d085 100644 --- a/Modules/Clients/Enums/RelationType.php +++ b/Modules/Clients/Enums/RelationType.php @@ -20,9 +20,9 @@ public static function values(): array public function label(): string { return match ($this) { - self::CUSTOMER => 'Customer', - self::VENDOR => 'Vendor', - self::PROSPECT => 'Prospect', + self::CUSTOMER => trans('ip.customer'), + self::VENDOR => trans('ip.vendor'), + self::PROSPECT => trans('ip.prospect'), self::PARTNER => 'Partner', self::LEAD => 'Lead', }; diff --git a/Modules/Core/Enums/NumberingType.php b/Modules/Core/Enums/NumberingType.php index a1a4dee69..196641a6b 100644 --- a/Modules/Core/Enums/NumberingType.php +++ b/Modules/Core/Enums/NumberingType.php @@ -22,13 +22,13 @@ public static function values(): array public function label(): string { return match ($this) { - self::CUSTOMER => 'Customer', - self::EXPENSE => 'Expense', - self::INVOICE => 'Invoice', - self::PAYMENT => 'Payment', - self::PROJECT => 'Project', - self::QUOTE => 'Quote', - self::TASK => 'Task', + self::CUSTOMER => trans('ip.customer'), + self::EXPENSE => trans('ip.expense'), + self::INVOICE => trans('ip.invoice'), + self::PAYMENT => trans('ip.payment'), + self::PROJECT => trans('ip.project'), + self::QUOTE => trans('ip.quote'), + self::TASK => trans('ip.task'), }; } diff --git a/Modules/Core/Enums/TaxRateType.php b/Modules/Core/Enums/TaxRateType.php index de4f7988d..77a1a59b1 100644 --- a/Modules/Core/Enums/TaxRateType.php +++ b/Modules/Core/Enums/TaxRateType.php @@ -21,7 +21,7 @@ public function label(): string return match ($this) { self::EXCLUSIVE => 'Exclusive', self::INCLUSIVE => 'Inclusive', - self::ZERO => 'Zero Rated', + self::ZERO => 'Zero', self::EXEMPT => 'Exempt', }; } diff --git a/Modules/Core/Filament/Company/Resources/Numberings/Tables/NumberingsTable.php b/Modules/Core/Filament/Company/Resources/Numberings/Tables/NumberingsTable.php index 29a94e26b..85042aeee 100644 --- a/Modules/Core/Filament/Company/Resources/Numberings/Tables/NumberingsTable.php +++ b/Modules/Core/Filament/Company/Resources/Numberings/Tables/NumberingsTable.php @@ -12,25 +12,25 @@ public static function configure(Table $table): Table return $table ->columns([ TextColumn::make('name') - ->label('Name') + ->label(trans('ip.name')) ->searchable() ->sortable(), TextColumn::make('type') - ->label('Type') + ->label(trans('ip.type')) ->searchable() ->sortable(), TextColumn::make('format') - ->label('Format') + ->label(trans('ip.format')) ->searchable(), TextColumn::make('next_id') - ->label('Next ID') + ->label(trans('ip.next_id')) ->sortable(), TextColumn::make('left_pad') - ->label('Padding'), + ->label(trans('ip.left_pad')), ]) ->defaultSort('type', 'asc'); } diff --git a/Modules/Core/Filament/Exporters/README.md b/Modules/Core/Filament/Exporters/README.md index 16356bd24..777abe9bb 100644 --- a/Modules/Core/Filament/Exporters/README.md +++ b/Modules/Core/Filament/Exporters/README.md @@ -4,7 +4,7 @@ This application uses Filament's export system, which handles exports **asynchronously via queued jobs**. -**⚠️ Queue Worker Required**: Export functionality requires a running queue worker to process export jobs. +** Queue Worker Required**: Export functionality requires a running queue worker to process export jobs. ## Queue Configuration @@ -93,8 +93,8 @@ Storage::fake('local'); // Act Livewire::actingAs($this->user) - ->test(ListExpenses::class) - ->callAction('exportCsvV2', data: [...]); + ->test(ListExpenses::class) + ->callAction('exportCsvV2', data: [...]); // Assert - verify job dispatching, not database records Bus::assertChained([...]); @@ -145,7 +145,7 @@ Schedule::command('model:prune')->daily(); By design, there is **no export history feature**. Users can export data when needed, download it immediately, and the system automatically cleans up the temporary records. This approach: -- ✅ Reduces database bloat -- ✅ Improves privacy (no lingering export data) -- ✅ Simplifies the system -- ✅ Follows the principle: "I don't need to see what I exported in the past" +- Reduces database bloat +- Improves privacy (no lingering export data) +- Simplifies the system +- Follows the principle: "I don't need to see what I exported in the past" diff --git a/Modules/Invoices/Peppol/FILES_CREATED.md b/Modules/Invoices/Peppol/FILES_CREATED.md index 9994e175f..82a0066af 100644 --- a/Modules/Invoices/Peppol/FILES_CREATED.md +++ b/Modules/Invoices/Peppol/FILES_CREATED.md @@ -9,147 +9,147 @@ This document provides a complete overview of all files created for the Peppol e ### Core HTTP Infrastructure (3 files) 1. **`Modules/Invoices/Http/Clients/ExternalClient.php`** - - Guzzle-like HTTP client wrapper using Laravel's Http facade - - Provides methods: request(), get(), post(), put(), patch(), delete() - - Supports base URL, headers, timeouts, authentication - - Lines: 299 + - Guzzle-like HTTP client wrapper using Laravel's Http facade + - Provides methods: request(), get(), post(), put(), patch(), delete() + - Supports base URL, headers, timeouts, authentication + - Lines: 299 2. **`Modules/Invoices/Http/Decorators/HttpClientExceptionHandler.php`** - - Decorator that adds exception handling and logging - - Sanitizes sensitive data in logs (API keys, auth tokens) - - Throws and logs RequestException, ConnectionException - - Lines: 274 + - Decorator that adds exception handling and logging + - Sanitizes sensitive data in logs (API keys, auth tokens) + - Throws and logs RequestException, ConnectionException + - Lines: 274 3. **`Modules/Invoices/Tests/Unit/Http/Clients/ExternalClientTest.php`** - - 18 unit tests for ExternalClient - - Tests GET, POST, PUT, PATCH, DELETE operations - - Tests error handling (404, 500, timeouts) - - Lines: 314 + - 18 unit tests for ExternalClient + - Tests GET, POST, PUT, PATCH, DELETE operations + - Tests error handling (404, 500, timeouts) + - Lines: 314 ### HTTP Decorator Tests (1 file) 4. **`Modules/Invoices/Tests/Unit/Http/Decorators/HttpClientExceptionHandlerTest.php`** - - 19 unit tests for HttpClientExceptionHandler - - Tests logging functionality (enable/disable) - - Tests sensitive data sanitization - - Tests error logging - - Lines: 353 + - 19 unit tests for HttpClientExceptionHandler + - Tests logging functionality (enable/disable) + - Tests sensitive data sanitization + - Tests error logging + - Lines: 353 ### Peppol Provider Base Classes (3 files) 5. **`Modules/Invoices/Peppol/Clients/BasePeppolClient.php`** - - Abstract base class for all Peppol providers - - Defines authentication header interface - - Configures HTTP client with base URL and timeouts - - Lines: 102 + - Abstract base class for all Peppol providers + - Defines authentication header interface + - Configures HTTP client with base URL and timeouts + - Lines: 102 6. **`Modules/Invoices/Peppol/Clients/EInvoiceBe/EInvoiceBeClient.php`** - - Concrete implementation for e-invoice.be provider - - Sets X-API-Key authentication header - - 90-second timeout for document operations - - Lines: 46 + - Concrete implementation for e-invoice.be provider + - Sets X-API-Key authentication header + - 90-second timeout for document operations + - Lines: 46 7. **`Modules/Invoices/Peppol/Clients/EInvoiceBe/DocumentsClient.php`** - - Client for document operations (submit, get, status, list, cancel) - - Implements e-invoice.be documents API endpoints - - Full PHPDoc for all methods - - Lines: 130 + - Client for document operations (submit, get, status, list, cancel) + - Implements e-invoice.be documents API endpoints + - Full PHPDoc for all methods + - Lines: 130 ### Peppol Client Tests (1 file) 8. **`Modules/Invoices/Tests/Unit/Peppol/Clients/DocumentsClientTest.php`** - - 12 unit tests for DocumentsClient - - Tests all document operations - - Tests authentication and error handling - - Lines: 305 + - 12 unit tests for DocumentsClient + - Tests all document operations + - Tests authentication and error handling + - Lines: 305 ### Peppol Service Layer (2 files) 9. **`Modules/Invoices/Peppol/Services/PeppolService.php`** - - Business logic for Peppol operations - - Invoice validation before sending - - Converts InvoicePlane invoices to Peppol UBL format - - Document status checking and cancellation - - Lines: 280 + - Business logic for Peppol operations + - Invoice validation before sending + - Converts InvoicePlane invoices to Peppol UBL format + - Document status checking and cancellation + - Lines: 280 10. **`Modules/Invoices/Tests/Unit/Peppol/Services/PeppolServiceTest.php`** - - 11 unit tests for PeppolService - - Tests validation (customer, invoice number, items) - - Tests error handling (API errors, timeouts, auth) - - Lines: 302 + - 11 unit tests for PeppolService + - Tests validation (customer, invoice number, items) + - Tests error handling (API errors, timeouts, auth) + - Lines: 302 ### Action Layer (2 files) 11. **`Modules/Invoices/Actions/SendInvoiceToPeppolAction.php`** - - Orchestrates invoice sending process - - Validates invoice state (rejects drafts) - - Provides status checking and cancellation methods - - Lines: 128 + - Orchestrates invoice sending process + - Validates invoice state (rejects drafts) + - Provides status checking and cancellation methods + - Lines: 128 12. **`Modules/Invoices/Tests/Unit/Actions/SendInvoiceToPeppolActionTest.php`** - - 11 unit tests for SendInvoiceToPeppolAction - - Tests invoice state validation - - Tests error scenarios - - Lines: 270 + - 11 unit tests for SendInvoiceToPeppolAction + - Tests invoice state validation + - Tests error scenarios + - Lines: 270 ### UI Integration (2 files) 13. **`Modules/Invoices/Filament/Company/Resources/Invoices/Pages/EditInvoice.php`** (modified) - - Added "Send to Peppol" header action - - Modal form for customer Peppol ID input - - Success/error notifications - - Added imports: Action, TextInput, Notification, SendInvoiceToPeppolAction + - Added "Send to Peppol" header action + - Modal form for customer Peppol ID input + - Success/error notifications + - Added imports: Action, TextInput, Notification, SendInvoiceToPeppolAction 14. **`Modules/Invoices/Filament/Company/Resources/Invoices/Tables/InvoicesTable.php`** (modified) - - Added "Send to Peppol" table action - - Same modal form and notifications as EditInvoice - - Added imports: TextInput, SendInvoiceToPeppolAction + - Added "Send to Peppol" table action + - Same modal form and notifications as EditInvoice + - Added imports: TextInput, SendInvoiceToPeppolAction ### Configuration & Service Provider (3 files) 15. **`Modules/Invoices/Config/config.php`** - - Peppol provider configuration - - e-invoice.be API settings - - Document format defaults (currency, unit codes) - - Validation settings - - Lines: 85 + - Peppol provider configuration + - e-invoice.be API settings + - Document format defaults (currency, unit codes) + - Validation settings + - Lines: 85 16. **`Modules/Invoices/Providers/InvoicesServiceProvider.php`** (modified) - - Added registerPeppolServices() method - - Registers ExternalClient, HttpClientExceptionHandler - - Registers DocumentsClient, PeppolService, SendInvoiceToPeppolAction - - Enables logging in non-production environments - - Configuration binding for API keys and base URLs + - Added registerPeppolServices() method + - Registers ExternalClient, HttpClientExceptionHandler + - Registers DocumentsClient, PeppolService, SendInvoiceToPeppolAction + - Enables logging in non-production environments + - Configuration binding for API keys and base URLs 17. **`resources/lang/en/ip.php`** (modified) - - Added 7 translation keys for Peppol: - - send_to_peppol - - customer_peppol_id - - customer_peppol_id_helper - - peppol_success_title - - peppol_success_body - - peppol_error_title - - peppol_error_body + - Added 7 translation keys for Peppol: + - send_to_peppol + - customer_peppol_id + - customer_peppol_id_helper + - peppol_success_title + - peppol_success_body + - peppol_error_title + - peppol_error_body ### Documentation (2 files) 18. **`Modules/Invoices/Peppol/README.md`** - - Comprehensive documentation (373 lines) - - Architecture overview - - Installation and configuration guide - - Usage examples (UI and programmatic) - - Data mapping documentation - - Error handling guide - - Testing documentation - - How to add new Peppol providers - - Troubleshooting tips + - Comprehensive documentation (373 lines) + - Architecture overview + - Installation and configuration guide + - Usage examples (UI and programmatic) + - Data mapping documentation + - Error handling guide + - Testing documentation + - How to add new Peppol providers + - Troubleshooting tips 19. **`Modules/Invoices/Peppol/.env.example`** - - Example environment configuration - - e-invoice.be settings - - Storecove placeholder (alternative provider) - - Commented documentation for each setting - - API documentation links + - Example environment configuration + - e-invoice.be settings + - Storecove placeholder (alternative provider) + - Commented documentation for each setting + - API documentation links 20. **`Modules/Invoices/Peppol/FILES_CREATED.md`** (this file) @@ -178,59 +178,44 @@ This document provides a complete overview of all files created for the Peppol e ## Key Features Implemented -✅ Modular HTTP client architecture -✅ Decorator pattern for exception handling -✅ Abstract base classes for multiple Peppol providers -✅ Complete e-invoice.be provider implementation -✅ Business logic service with validation -✅ Action layer for UI integration -✅ Full UI integration in EditInvoice and ListInvoices -✅ Comprehensive error handling and logging -✅ Extensive PHPDoc documentation -✅ 71 unit tests with fakes (not mocks) -✅ Configuration management -✅ Translation support -✅ README documentation -✅ Example environment configuration + Modular HTTP client architecture + Decorator pattern for exception handling + Abstract base classes for multiple Peppol providers + Complete e-invoice.be provider implementation + Business logic service with validation + Action layer for UI integration + Full UI integration in EditInvoice and ListInvoices + Comprehensive error handling and logging + Extensive PHPDoc documentation + 71 unit tests with fakes (not mocks) + Configuration management + Translation support + README documentation + Example environment configuration ## Architecture Diagram ``` -┌─────────────────────────────────────────────────────────┐ -│ UI Layer │ -│ EditInvoice Action │ ListInvoices Table Action │ -└────────────────────┬────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────┐ -│ Action Layer │ -│ SendInvoiceToPeppolAction │ -└────────────────────┬────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────┐ -│ Service Layer │ -│ PeppolService │ -│ (Validation, Data Preparation, Business Logic) │ -└────────────────────┬────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────┐ -│ Peppol Client Layer │ -│ DocumentsClient → EInvoiceBeClient → BasePeppolClient │ -└────────────────────┬────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────┐ -│ HTTP Client Layer │ -│ HttpClientExceptionHandler → ExternalClient │ -│ (Decorator Pattern) │ -└────────────────────┬────────────────────────────────────┘ - │ - ▼ -┌─────────────────────────────────────────────────────────┐ -│ Laravel Http Facade │ -└─────────────────────────────────────────────────────────┘ + + UI Layer + EditInvoice Action ListInvoices Table Action + + Action Layer + SendInvoiceToPeppolAction + + Service Layer + PeppolService + (Validation, Data Preparation, Business Logic) + + Peppol Client Layer + DocumentsClient → EInvoiceBeClient → BasePeppolClient + + HTTP Client Layer + HttpClientExceptionHandler → ExternalClient + (Decorator Pattern) + + Laravel Http Facade + ``` ## Dependencies diff --git a/Modules/Invoices/Peppol/IMPLEMENTATION_SUMMARY.md b/Modules/Invoices/Peppol/IMPLEMENTATION_SUMMARY.md index 27451aa38..0703e078f 100644 --- a/Modules/Invoices/Peppol/IMPLEMENTATION_SUMMARY.md +++ b/Modules/Invoices/Peppol/IMPLEMENTATION_SUMMARY.md @@ -5,19 +5,19 @@ Complete Peppol e-invoicing integration for InvoicePlane v2 with extensive forma ## Architecture Layers -### 1. HTTP Client Layer ✅ +### 1. HTTP Client Layer - **ApiClient**: Simplified single `request()` method using Laravel Http facade - **RequestMethod Enum**: Type-safe HTTP method constants - **HttpClientExceptionHandler**: Decorator with exception handling and logging - **LogsApiRequests Trait**: Centralized API request/response logging with sensitive data sanitization -### 2. Configuration Layer ✅ +### 2. Configuration Layer - **Comprehensive Config**: Currency, supplier details, endpoint schemes by country - **Format Settings**: UBL, CII customization IDs and profiles - **Validation Rules**: Configurable requirements for Peppol transmission - **Feature Flags**: Enable/disable tracking, webhooks, participant search, health checks -### 3. Enums & Data Structures ✅ +### 3. Enums & Data Structures #### PeppolDocumentFormat (11 formats) - UBL 2.1/2.4, CII, PEPPOL BIS 3.0 @@ -33,7 +33,7 @@ Complete Peppol e-invoicing integration for InvoicePlane v2 with extensive forma - Automatic scheme selection based on country - Format validation and identifier formatting -### 4. Format Handlers (Strategy Pattern) ✅ +### 4. Format Handlers (Strategy Pattern) #### Interface & Base - **InvoiceFormatHandlerInterface**: Contract for all handlers @@ -45,12 +45,12 @@ Complete Peppol e-invoicing integration for InvoicePlane v2 with extensive forma #### Factory - **FormatHandlerFactory**: Automatic handler selection based on: - 1. Customer's preferred format - 2. Mandatory format for country - 3. Recommended format - 4. Default PEPPOL BIS fallback + 1. Customer's preferred format + 2. Mandatory format for country + 3. Recommended format + 4. Default PEPPOL BIS fallback -### 5. API Clients (Complete e-invoice.be Coverage) ✅ +### 5. API Clients (Complete e-invoice.be Coverage) #### DocumentsClient - submitDocument() - Send invoices @@ -88,18 +88,18 @@ Complete Peppol e-invoicing integration for InvoicePlane v2 with extensive forma - checkReadiness() - Load balancer check - checkLiveness() - Orchestrator check -### 6. Service Layer ✅ +### 6. Service Layer - **PeppolService**: - - Integrated with LogsApiRequests trait - - Uses FormatHandlerFactory for automatic format selection - - Format-specific validation - - Comprehensive error handling with format context + - Integrated with LogsApiRequests trait + - Uses FormatHandlerFactory for automatic format selection + - Format-specific validation + - Comprehensive error handling with format context -### 7. Database & Models ✅ +### 7. Database & Models - **Migration**: add_peppol_fields_to_relations_table - - peppol_id (string) - Customer Peppol identifier - - peppol_format (string) - Preferred document format - - enable_e_invoicing (boolean) - Toggle per customer + - peppol_id (string) - Customer Peppol identifier + - peppol_format (string) - Preferred document format + - enable_e_invoicing (boolean) - Toggle per customer - **Relation Model**: Updated with Peppol properties and casting ## Configuration Examples @@ -143,11 +143,11 @@ $result = $peppolService->sendInvoiceToPeppol($invoice); // Returns: // [ -// 'success' => true, -// 'document_id' => 'DOC-123', -// 'status' => 'submitted', -// 'format' => 'peppol_bis_3.0', -// 'message' => 'Invoice successfully submitted' +// 'success' => true, +// 'document_id' => 'DOC-123', +// 'status' => 'submitted', +// 'format' => 'peppol_bis_3.0', +// 'message' => 'Invoice successfully submitted' // ] ``` diff --git a/Modules/Invoices/Peppol/README.md b/Modules/Invoices/Peppol/README.md index 194f9f7c0..3c6557dff 100644 --- a/Modules/Invoices/Peppol/README.md +++ b/Modules/Invoices/Peppol/README.md @@ -9,26 +9,26 @@ This Peppol integration allows InvoicePlane v2 to send invoices electronically t ### Components 1. **HTTP Client Layer** - - HTTP client: Laravel's Http facade wrapper - - Comprehensive exception handling and logging for all API requests + - HTTP client: Laravel's Http facade wrapper + - Comprehensive exception handling and logging for all API requests 2. **Peppol Provider Layer** - - `BasePeppolClient`: Abstract base class for all Peppol providers - - `EInvoiceBeClient`: Concrete implementation for e-invoice.be provider - - `DocumentsClient`: Specific client for document operations + - `BasePeppolClient`: Abstract base class for all Peppol providers + - `EInvoiceBeClient`: Concrete implementation for e-invoice.be provider + - `DocumentsClient`: Specific client for document operations 3. **Service Layer** - - `PeppolService`: Business logic for Peppol operations - - Handles invoice validation, data preparation, and transmission + - `PeppolService`: Business logic for Peppol operations + - Handles invoice validation, data preparation, and transmission 4. **Action Layer** - - `SendInvoiceToPeppolAction`: Orchestrates invoice sending process - - Can be called from UI actions or programmatically + - `SendInvoiceToPeppolAction`: Orchestrates invoice sending process + - Can be called from UI actions or programmatically 5. **UI Integration** - - Header action in `EditInvoice` page - - Table action in `ListInvoices` page - - Modal form for entering customer Peppol ID + - Header action in `EditInvoice` page + - Table action in `ListInvoices` page + - Modal form for entering customer Peppol ID ## Installation & Configuration @@ -87,21 +87,21 @@ $invoice = Invoice::find($invoiceId); $action = app(SendInvoiceToPeppolAction::class); try { - $result = $action->execute($invoice, [ - 'customer_peppol_id' => 'BE:0123456789', - ]); - - // Success! Document ID is available - $documentId = $result['document_id']; - $status = $result['status']; - + $result = $action->execute($invoice, [ + 'customer_peppol_id' => 'BE:0123456789', + ]); + + // Success! Document ID is available + $documentId = $result['document_id']; + $status = $result['status']; + } catch (\InvalidArgumentException $e) { - // Validation error - Log::error('Invalid invoice data: ' . $e->getMessage()); - + // Validation error + Log::error('Invalid invoice data: ' . $e->getMessage()); + } catch (\Illuminate\Http\Client\RequestException $e) { - // API request failed - Log::error('Peppol API error: ' . $e->getMessage()); + // API request failed + Log::error('Peppol API error: ' . $e->getMessage()); } ``` @@ -113,9 +113,9 @@ $status = $action->getStatus('DOC-123456'); // Returns: // [ -// 'status' => 'delivered', -// 'delivered_at' => '2024-01-15T12:30:00Z', -// ... +// 'status' => 'delivered', +// 'delivered_at' => '2024-01-15T12:30:00Z', +// ... // ] ``` @@ -134,47 +134,47 @@ The `PeppolService` transforms InvoicePlane invoices to Peppol UBL format: ```php [ - 'document_type' => 'invoice', - 'invoice_number' => 'INV-2024-001', - 'issue_date' => '2024-01-15', - 'due_date' => '2024-02-14', - 'currency_code' => 'EUR', - - 'supplier' => [ - 'name' => 'Company Name', - // Additional supplier details - ], - - 'customer' => [ - 'name' => 'Customer Name', - 'endpoint_id' => 'BE:0123456789', - 'endpoint_scheme' => 'BE:CBE', - ], - - 'invoice_lines' => [ - [ - 'id' => 1, - 'quantity' => 2, - 'unit_code' => 'C62', - 'line_extension_amount' => 200.00, - 'price_amount' => 100.00, - 'item' => [ - 'name' => 'Product Name', - 'description' => 'Product description', - ], - ], - ], - - 'legal_monetary_total' => [ - 'line_extension_amount' => 200.00, - 'tax_exclusive_amount' => 200.00, - 'tax_inclusive_amount' => 242.00, - 'payable_amount' => 242.00, - ], - - 'tax_total' => [ - 'tax_amount' => 42.00, - ], + 'document_type' => 'invoice', + 'invoice_number' => 'INV-2024-001', + 'issue_date' => '2024-01-15', + 'due_date' => '2024-02-14', + 'currency_code' => 'EUR', + + 'supplier' => [ + 'name' => 'Company Name', + // Additional supplier details + ], + + 'customer' => [ + 'name' => 'Customer Name', + 'endpoint_id' => 'BE:0123456789', + 'endpoint_scheme' => 'BE:CBE', + ], + + 'invoice_lines' => [ + [ + 'id' => 1, + 'quantity' => 2, + 'unit_code' => 'C62', + 'line_extension_amount' => 200.00, + 'price_amount' => 100.00, + 'item' => [ + 'name' => 'Product Name', + 'description' => 'Product description', + ], + ], + ], + + 'legal_monetary_total' => [ + 'line_extension_amount' => 200.00, + 'tax_exclusive_amount' => 200.00, + 'tax_inclusive_amount' => 242.00, + 'payable_amount' => 242.00, + ], + + 'tax_total' => [ + 'tax_amount' => 42.00, + ], ] ``` @@ -182,11 +182,11 @@ The `PeppolService` transforms InvoicePlane invoices to Peppol UBL format: Before sending to Peppol, invoices are validated: -- ✅ Must have a customer -- ✅ Must have an invoice number -- ✅ Must have at least one invoice item -- ✅ Cannot be in draft status -- ✅ Customer Peppol ID must be provided +- Must have a customer +- Must have an invoice number +- Must have at least one invoice item +- Cannot be in draft status +- Customer Peppol ID must be provided ## Error Handling @@ -231,26 +231,26 @@ Tests use Laravel's HTTP fakes instead of mocks: use Illuminate\Support\Facades\Http; Http::fake([ - 'https://api.e-invoice.be/*' => Http::response([ - 'document_id' => 'DOC-123', - 'status' => 'submitted', - ], 200), + 'https://api.e-invoice.be/*' => Http::response([ + 'document_id' => 'DOC-123', + 'status' => 'submitted', + ], 200), ]); // Your test code here Http::assertSent(function ($request) { - return $request->url() === 'https://api.e-invoice.be/api/documents'; + return $request->url() === 'https://api.e-invoice.be/api/documents'; }); ``` ### Test Coverage -- ✅ `ExternalClientTest`: 15 tests (HTTP wrapper) -- ✅ `HttpClientExceptionHandlerTest`: Not yet implemented -- ✅ `DocumentsClientTest`: 12 tests (API client) -- ✅ `PeppolServiceTest`: 11 tests (Business logic) -- ✅ `SendInvoiceToPeppolActionTest`: 11 tests (Action) +- `ExternalClientTest`: 15 tests (HTTP wrapper) +- `HttpClientExceptionHandlerTest`: Not yet implemented +- `DocumentsClientTest`: 12 tests (API client) +- `PeppolServiceTest`: 11 tests (Business logic) +- `SendInvoiceToPeppolActionTest`: 11 tests (Action) Total: **49 unit tests** covering success and failure scenarios @@ -264,13 +264,13 @@ namespace Modules\Invoices\Peppol\Clients\Storecove; class StorecoveClient extends BasePeppolClient { - protected function getAuthenticationHeaders(): array - { - return [ - 'Authorization' => 'Bearer ' . $this->apiKey, - 'Content-Type' => 'application/json', - ]; - } + protected function getAuthenticationHeaders(): array + { + return [ + 'Authorization' => 'Bearer ' . $this->apiKey, + 'Content-Type' => 'application/json', + ]; + } } ``` @@ -278,33 +278,33 @@ class StorecoveClient extends BasePeppolClient ```php class StorecoveDocumentsClient extends StorecoveClient { - public function submitDocument(array $data): Response - { - return $this->client->post('documents', $data); - } + public function submitDocument(array $data): Response + { + return $this->client->post('documents', $data); + } } ``` 3. Register in `InvoicesServiceProvider`: ```php $this->app->bind( - StorecoveDocumentsClient::class, - function ($app) { - $handler = $app->make(HttpClientExceptionHandler::class); - return new StorecoveDocumentsClient( - $handler, - config('invoices.peppol.storecove.api_key'), - config('invoices.peppol.storecove.base_url') - ); - } + StorecoveDocumentsClient::class, + function ($app) { + $handler = $app->make(HttpClientExceptionHandler::class); + return new StorecoveDocumentsClient( + $handler, + config('invoices.peppol.storecove.api_key'), + config('invoices.peppol.storecove.base_url') + ); + } ); ``` 4. Update configuration in `config.php`: ```php 'storecove' => [ - 'api_key' => env('PEPPOL_STORECOVE_API_KEY', ''), - 'base_url' => env('PEPPOL_STORECOVE_BASE_URL', 'https://api.storecove.com'), + 'api_key' => env('PEPPOL_STORECOVE_API_KEY', ''), + 'base_url' => env('PEPPOL_STORECOVE_BASE_URL', 'https://api.storecove.com'), ], ``` @@ -365,7 +365,7 @@ Increase timeout in provider client: ```php protected function getTimeout(): int { - return 120; // 2 minutes + return 120; // 2 minutes } ``` @@ -388,7 +388,7 @@ InvoicePlane v2 supports 11 different e-invoice formats to comply with various n - **Handler**: `PeppolBisHandler` - **Profile**: `urn:fdc:peppol.eu:2017:poacc:billing:01:1.0` - **Use case**: Default format for cross-border invoicing in Europe -- **Status**: ✅ Fully implemented +- **Status**: Fully implemented #### UBL 2.1 / 2.4 - **Format**: OASIS Universal Business Language @@ -396,7 +396,7 @@ InvoicePlane v2 supports 11 different e-invoice formats to comply with various n - **Handler**: `UblHandler` - **Standards**: [OASIS UBL](http://docs.oasis-open.org/ubl/) - **Use case**: General-purpose e-invoicing -- **Status**: ✅ Fully implemented +- **Status**: Fully implemented #### CII (Cross Industry Invoice) - **Format**: UN/CEFACT XML @@ -404,7 +404,7 @@ InvoicePlane v2 supports 11 different e-invoice formats to comply with various n - **Handler**: `CiiHandler` - **Standard**: UN/CEFACT D16B - **Use case**: Alternative to UBL, common in Central Europe -- **Status**: ✅ Fully implemented +- **Status**: Fully implemented ### Country-Specific Formats @@ -414,14 +414,14 @@ InvoicePlane v2 supports 11 different e-invoice formats to comply with various n - **Handler**: `FatturaPaHandler` - **Authority**: Agenzia delle Entrate - **Requirements**: - - Supplier: Italian VAT number (Partita IVA) - - Customer: Tax code (Codice Fiscale) for Italian customers - - Transmission: Via SDI (Sistema di Interscambio) + - Supplier: Italian VAT number (Partita IVA) + - Customer: Tax code (Codice Fiscale) for Italian customers + - Transmission: Via SDI (Sistema di Interscambio) - **Features**: - - Fiscal regime codes - - Payment conditions - - Tax summary by rate -- **Status**: ✅ Fully implemented + - Fiscal regime codes + - Payment conditions + - Tax summary by rate +- **Status**: Fully implemented #### Facturae 3.2 (Spain) - **Format**: XML @@ -429,14 +429,14 @@ InvoicePlane v2 supports 11 different e-invoice formats to comply with various n - **Handler**: `FacturaeHandler` - **Authority**: Ministry of Finance and Public Administration - **Requirements**: - - Supplier: Spanish tax ID (NIF/CIF) - - Format includes: File header, parties, invoices - - Support for both resident and overseas addresses + - Supplier: Spanish tax ID (NIF/CIF) + - Format includes: File header, parties, invoices + - Support for both resident and overseas addresses - **Features**: - - Series codes for invoice numbering - - Administrative centres - - IVA (Spanish VAT) handling -- **Status**: ✅ Fully implemented + - Series codes for invoice numbering + - Administrative centres + - IVA (Spanish VAT) handling +- **Status**: Fully implemented #### Factur-X 1.0 (France/Germany) - **Format**: PDF/A-3 with embedded CII XML @@ -444,15 +444,15 @@ InvoicePlane v2 supports 11 different e-invoice formats to comply with various n - **Handler**: `FacturXHandler` - **Standards**: Hybrid of PDF and XML - **Requirements**: - - Supplier: VAT number - - PDF must be PDF/A-3 compliant - - XML embedded as attachment + - Supplier: VAT number + - PDF must be PDF/A-3 compliant + - XML embedded as attachment - **Features**: - - Human-readable PDF - - Machine-readable XML - - Compatible with ZUGFeRD 2.0 + - Human-readable PDF + - Machine-readable XML + - Compatible with ZUGFeRD 2.0 - **Profiles**: MINIMUM, BASIC, EN16931, EXTENDED -- **Status**: ✅ Fully implemented +- **Status**: Fully implemented #### ZUGFeRD 1.0 / 2.0 (Germany) - **Format**: PDF/A-3 with embedded XML (1.0) or CII XML (2.0) @@ -460,17 +460,17 @@ InvoicePlane v2 supports 11 different e-invoice formats to comply with various n - **Handler**: `ZugferdHandler` - **Authority**: FeRD (Forum elektronische Rechnung Deutschland) - **Requirements**: - - Supplier: German VAT number - - SEPA payment means support - - German-specific tax handling + - Supplier: German VAT number + - SEPA payment means support + - German-specific tax handling - **Versions**: - - **1.0**: Original ZUGFeRD format - - **2.0**: Compatible with Factur-X, uses EN 16931 + - **1.0**: Original ZUGFeRD format + - **2.0**: Compatible with Factur-X, uses EN 16931 - **Features**: - - Multiple profiles (Comfort, Basic, Extended) - - SEPA credit transfer codes - - German VAT rate (19% standard) -- **Status**: ✅ Fully implemented (both versions) + - Multiple profiles (Comfort, Basic, Extended) + - SEPA credit transfer codes + - German VAT rate (19% standard) +- **Status**: Fully implemented (both versions) #### OIOUBL (Denmark) - **Format**: UBL 2.0 with Danish extensions @@ -478,16 +478,16 @@ InvoicePlane v2 supports 11 different e-invoice formats to comply with various n - **Handler**: `OioublHandler` - **Authority**: Digitaliseringsstyrelsen - **Requirements**: - - Supplier: CVR number (Danish business registration) - - Customer: Peppol ID (CVR for Danish entities) - - Accounting cost codes + - Supplier: CVR number (Danish business registration) + - Customer: Peppol ID (CVR for Danish entities) + - Accounting cost codes - **Features**: - - Danish-specific party identification - - Payment means with bank details - - Settlement periods - - Danish VAT (25% standard) + - Danish-specific party identification + - Payment means with bank details + - Settlement periods + - Danish VAT (25% standard) - **Profile**: `Procurement-OrdSim-BilSim-1.0` -- **Status**: ✅ Fully implemented +- **Status**: Fully implemented #### EHF 3.0 (Norway) - **Format**: UBL 2.1 with Norwegian extensions @@ -495,16 +495,16 @@ InvoicePlane v2 supports 11 different e-invoice formats to comply with various n - **Handler**: `EhfHandler` - **Authority**: Difi (Agency for Public Management and eGovernment) - **Requirements**: - - Supplier: Norwegian organization number (ORGNR) - - Customer: Organization number or Peppol ID - - Buyer reference for routing + - Supplier: Norwegian organization number (ORGNR) + - Customer: Organization number or Peppol ID + - Buyer reference for routing - **Features**: - - Norwegian organization numbers (9 digits) - - Delivery information - - Norwegian payment terms - - Norwegian VAT (25% standard) + - Norwegian organization numbers (9 digits) + - Delivery information + - Norwegian payment terms + - Norwegian VAT (25% standard) - **Profile**: PEPPOL BIS 3.0 compliant -- **Status**: ✅ Fully implemented +- **Status**: Fully implemented ### Format Selection @@ -518,14 +518,14 @@ The system automatically selects the appropriate format based on: #### Format Recommendations by Country ```php -'ES' => Facturae 3.2 // Spain -'IT' => FatturaPA 1.2 // Italy (mandatory) -'FR' => Factur-X 1.0 // France -'DE' => ZUGFeRD 2.0 // Germany -'AT' => CII // Austria -'DK' => OIOUBL // Denmark -'NO' => EHF // Norway -'*' => PEPPOL BIS 3.0 // Default for all other countries +'ES' => Facturae 3.2 // Spain +'IT' => FatturaPA 1.2 // Italy (mandatory) +'FR' => Factur-X 1.0 // France +'DE' => ZUGFeRD 2.0 // Germany +'AT' => CII // Austria +'DK' => OIOUBL // Denmark +'NO' => EHF // Norway +'*' => PEPPOL BIS 3.0 // Default for all other countries ``` ### Endpoint Schemes by Country @@ -564,10 +564,10 @@ php artisan test Modules/Invoices/Tests/Unit/Peppol/FormatHandlers/FatturaPaHand ### Test Coverage -- ✅ **PeppolEndpointSchemeTest**: 240+ assertions covering all 17 endpoint schemes -- ✅ **FatturaPaHandlerTest**: Italian FatturaPA format validation and transformation -- ✅ **FormatHandlersTest**: Comprehensive tests for all 5 new handlers (Facturae, Factur-X, ZUGFeRD, OIOUBL, EHF) -- ✅ **PeppolDocumentFormatTest**: Format enum validation and country recommendations +- **PeppolEndpointSchemeTest**: 240+ assertions covering all 17 endpoint schemes +- **FatturaPaHandlerTest**: Italian FatturaPA format validation and transformation +- **FormatHandlersTest**: Comprehensive tests for all 5 new handlers (Facturae, Factur-X, ZUGFeRD, OIOUBL, EHF) +- **PeppolDocumentFormatTest**: Format enum validation and country recommendations Total test count: **90+ unit tests** covering all formats and handlers diff --git a/Modules/ReportBuilder/Enums/ReportTemplateType.php b/Modules/ReportBuilder/Enums/ReportTemplateType.php new file mode 100644 index 000000000..c220e9454 --- /dev/null +++ b/Modules/ReportBuilder/Enums/ReportTemplateType.php @@ -0,0 +1,35 @@ + trans('ip.invoice'), + self::QUOTE => trans('ip.quote'), + self::ESTIMATE => trans('ip.estimate'), + }; + } + + public function color(): string + { + return match ($this) { + self::INVOICE => 'success', + self::QUOTE => 'info', + self::ESTIMATE => 'warning', + }; + } +} diff --git a/Modules/ReportBuilder/Filament/Admin/Resources/ReportTemplateResource/Schemas/ReportTemplateForm.php b/Modules/ReportBuilder/Filament/Admin/Resources/ReportTemplateResource/Schemas/ReportTemplateForm.php index 6e3fa0b9d..05710e768 100644 --- a/Modules/ReportBuilder/Filament/Admin/Resources/ReportTemplateResource/Schemas/ReportTemplateForm.php +++ b/Modules/ReportBuilder/Filament/Admin/Resources/ReportTemplateResource/Schemas/ReportTemplateForm.php @@ -9,6 +9,7 @@ use Filament\Schemas\Components\Grid; use Filament\Schemas\Components\Section; use Filament\Schemas\Schema; +use Modules\ReportBuilder\Enums\ReportTemplateType; class ReportTemplateForm { @@ -21,29 +22,28 @@ public static function configure(Schema $schema): Schema Grid::make(2) ->schema([ TextInput::make('name') - ->label('Template Name') + ->label(trans('ip.template_name')) ->required() ->maxLength(255), Select::make('template_type') - ->label('Template Type') + ->label(trans('ip.template_type')) ->required() - ->options([ - 'invoice' => 'Invoice', - 'quote' => 'Quote', - 'estimate' => 'Estimate', - ]), + ->options( + collect(ReportTemplateType::cases()) + ->mapWithKeys(fn ($type) => [$type->value => $type->label()]) + ), ]), Textarea::make('description') - ->label('Description') + ->label(trans('ip.description')) ->rows(3) ->maxLength(1000), Grid::make(2) ->schema([ Checkbox::make('is_active') - ->label('Active') + ->label(trans('ip.active')) ->default(true), Checkbox::make('is_system') - ->label('System Template') + ->label(trans('ip.system_template')) ->disabled() ->dehydrated(false), ]), diff --git a/Modules/ReportBuilder/Filament/Admin/Resources/ReportTemplateResource/Tables/ReportTemplatesTable.php b/Modules/ReportBuilder/Filament/Admin/Resources/ReportTemplateResource/Tables/ReportTemplatesTable.php index 22871f7de..b8244b225 100644 --- a/Modules/ReportBuilder/Filament/Admin/Resources/ReportTemplateResource/Tables/ReportTemplatesTable.php +++ b/Modules/ReportBuilder/Filament/Admin/Resources/ReportTemplateResource/Tables/ReportTemplatesTable.php @@ -13,6 +13,7 @@ use Filament\Tables\Filters\SelectFilter; use Filament\Tables\Filters\TernaryFilter; use Filament\Tables\Table; +use Modules\ReportBuilder\Enums\ReportTemplateType; use Modules\ReportBuilder\Models\ReportTemplate; use Modules\ReportBuilder\Services\ReportTemplateService; @@ -23,34 +24,37 @@ public static function configure(Table $table): Table return $table ->columns([ TextColumn::make('id') - ->label('ID') + ->label(trans('ip.id')) ->sortable() ->toggleable(), TextColumn::make('name') + ->label(trans('ip.name')) ->searchable() ->sortable() ->toggleable(), TextColumn::make('slug') + ->label(trans('ip.slug')) ->searchable() ->sortable() ->toggleable(), TextColumn::make('template_type') - ->label('Type') + ->label(trans('ip.type')) ->badge() ->searchable() ->sortable() ->toggleable(), IconColumn::make('is_system') - ->label('System') + ->label(trans('ip.system')) ->boolean() ->sortable() ->toggleable(), IconColumn::make('is_active') - ->label('Active') + ->label(trans('ip.active')) ->boolean() ->sortable() ->toggleable(), TextColumn::make('created_at') + ->label(trans('ip.created_at')) ->dateTime() ->sortable() ->toggleable() @@ -58,14 +62,13 @@ public static function configure(Table $table): Table ]) ->filters([ SelectFilter::make('template_type') - ->label('Template Type') - ->options([ - 'invoice' => 'Invoice', - 'quote' => 'Quote', - 'estimate' => 'Estimate', - ]), + ->label(trans('ip.template_type')) + ->options( + collect(ReportTemplateType::cases()) + ->mapWithKeys(fn ($type) => [$type->value => $type->label()]) + ), TernaryFilter::make('is_active') - ->label('Active') + ->label(trans('ip.active')) ->nullable(), ]) ->recordActions([ @@ -81,12 +84,12 @@ public static function configure(Table $table): Table ->modalWidth('full') ->visible(fn (ReportTemplate $record) => ! $record->is_system), Action::make('design') - ->label('Design') + ->label(trans('ip.design')) ->icon(Heroicon::OutlinedPaintBrush) ->url(fn (ReportTemplate $record) => route('filament.admin.resources.report-templates.design', ['record' => $record->id])) ->visible(fn (ReportTemplate $record) => ! $record->is_system), Action::make('clone') - ->label('Clone') + ->label(trans('ip.clone')) ->icon(Heroicon::OutlinedDocumentDuplicate) ->requiresConfirmation() ->action(function (ReportTemplate $record) { diff --git a/Modules/ReportBuilder/Models/ReportTemplate.php b/Modules/ReportBuilder/Models/ReportTemplate.php index 2ba5a5a97..9c791895d 100644 --- a/Modules/ReportBuilder/Models/ReportTemplate.php +++ b/Modules/ReportBuilder/Models/ReportTemplate.php @@ -4,16 +4,17 @@ use Illuminate\Database\Eloquent\Model; use Modules\Core\Traits\BelongsToCompany; +use Modules\ReportBuilder\Enums\ReportTemplateType; /** - * @property int $id - * @property int $company_id - * @property string $name - * @property string $slug - * @property string|null $description - * @property string $template_type - * @property bool $is_system - * @property bool $is_active + * @property int $id + * @property int $company_id + * @property string $name + * @property string $slug + * @property string|null $description + * @property ReportTemplateType $template_type + * @property bool $is_system + * @property bool $is_active */ class ReportTemplate extends Model { @@ -32,7 +33,7 @@ class ReportTemplate extends Model protected $casts = [ 'is_system' => 'boolean', 'is_active' => 'boolean', - 'template_type' => 'string', + 'template_type' => ReportTemplateType::class, ]; /** diff --git a/PEPPOL_ARCHITECTURE.md b/PEPPOL_ARCHITECTURE.md index 696583db8..160892303 100644 --- a/PEPPOL_ARCHITECTURE.md +++ b/PEPPOL_ARCHITECTURE.md @@ -6,7 +6,7 @@ This document provides a comprehensive summary of the PEPPOL e-invoicing archite ## Architecture Components Implemented -### 1. Database Layer ✅ +### 1. Database Layer #### Migrations Created: - `2025_10_02_000001_create_peppol_integrations_table.php` @@ -20,7 +20,7 @@ This document provides a comprehensive summary of the PEPPOL e-invoicing archite - `CustomerPeppolValidationHistory` - Audits all customer Peppol ID validations - Updated `Relation` (Customer) model with Peppol fields and validation status -### 2. Provider Abstraction Layer ✅ +### 2. Provider Abstraction Layer #### Core Interfaces & Factories: - `ProviderInterface` - Contract that all providers must implement @@ -39,7 +39,7 @@ This document provides a comprehensive summary of the PEPPOL e-invoicing archite - `cancelDocument()` - Cancel pending transmissions - `classifyError()` - Categorize errors as TRANSIENT/PERMANENT/UNKNOWN -### 3. Events & Audit Trail ✅ +### 3. Events & Audit Trail **Events Implemented:** - `PeppolIntegrationCreated` @@ -56,30 +56,30 @@ This document provides a comprehensive summary of the PEPPOL e-invoicing archite - `LogPeppolEventToAudit` listener logs all events to `audit_log` table - Complete event payload preserved for compliance -### 4. Background Jobs & Queue Processing ✅ +### 4. Background Jobs & Queue Processing **Jobs Implemented:** - `SendInvoiceToPeppolJob` - Main orchestration job for sending invoices - - Pre-send validation - - Idempotency guards - - Artifact generation (XML/PDF) - - Provider transmission - - Retry scheduling with exponential backoff - + - Pre-send validation + - Idempotency guards + - Artifact generation (XML/PDF) + - Provider transmission + - Retry scheduling with exponential backoff + - `PeppolStatusPoller` - Polls providers for acknowledgements - - Batch processes transmissions awaiting ACK - - Updates status to accepted/rejected - + - Batch processes transmissions awaiting ACK + - Updates status to accepted/rejected + - `RetryFailedTransmissions` - Retry scheduler - - Respects max attempts limit - - Marks as dead when exceeded + - Respects max attempts limit + - Marks as dead when exceeded **Console Commands:** - `peppol:poll-status` - Dispatch status polling job - `peppol:retry-failed` - Dispatch retry job - `peppol:test-integration` - Test connection for an integration -### 5. Services & Business Logic ✅ +### 5. Services & Business Logic **PeppolManagementService:** - `createIntegration()` - Create new provider integration @@ -94,13 +94,13 @@ This document provides a comprehensive summary of the PEPPOL e-invoicing archite - Extracts supplier, customer, line items, tax totals - Formats dates, amounts, and codes per Peppol requirements -### 6. State Machine Implementation ✅ +### 6. State Machine Implementation **Transmission States:** ``` pending → queued → processing → sent → accepted - ↘ rejected - ↘ failed → retrying → (back to processing or dead) + ↘ rejected + ↘ failed → retrying → (back to processing or dead) ``` **State Machine Methods on PeppolTransmission:** @@ -116,7 +116,7 @@ pending → queued → processing → sent → accepted - `canRetry()` - Check if retry is allowed - `isAwaitingAck()` - Check if waiting for acknowledgement -### 7. Error Handling & Classification ✅ +### 7. Error Handling & Classification **Error Types:** - `TRANSIENT` - 5xx errors, timeouts, rate limits (retryable) @@ -129,7 +129,7 @@ pending → queued → processing → sent → accepted - Automatic dead-letter marking after max attempts - Manual retry capability via UI actions -### 8. Configuration ✅ +### 8. Configuration **Comprehensive Config in `Modules/Invoices/Config/config.php`:** @@ -144,13 +144,13 @@ pending → queued → processing → sent → accepted - **Storage** settings for artifacts - **Monitoring** thresholds and alerts -### 9. Storage & Artifacts ✅ +### 9. Storage & Artifacts **Storage Structure:** ``` peppol/{integration_id}/{year}/{month}/{transmission_id}/ - - invoice.xml - - invoice.pdf + - invoice.xml + - invoice.pdf ``` **Implemented in SendInvoiceToPeppolJob:** @@ -159,7 +159,7 @@ peppol/{integration_id}/{year}/{month}/{transmission_id}/ - Records paths in transmission record - Configurable retention period -### 10. Idempotency & Concurrency ✅ +### 10. Idempotency & Concurrency **Idempotency:** - Unique idempotency key calculated from: `hash(invoice_id|customer_peppol_id|integration_id|updated_at)` @@ -209,7 +209,7 @@ peppol/{integration_id}/{year}/{month}/{transmission_id}/ ## Implementation Status -### ✅ Completed +### Completed - [x] Database migrations (4 tables) - [x] Models (3 new + 1 updated) @@ -226,7 +226,7 @@ peppol/{integration_id}/{year}/{month}/{transmission_id}/ - [x] Idempotency - [x] Storage structure -### 🚧 Partial / Needs UI Integration +### Partial / Needs UI Integration - [ ] Filament Resources (PeppolIntegration CRUD) - [ ] Customer Peppol validation UI @@ -235,7 +235,7 @@ peppol/{integration_id}/{year}/{month}/{transmission_id}/ - [ ] Webhook receiver endpoint - [ ] Dashboard widgets -### 📝 TODO (Additional Enhancements) +### TODO (Additional Enhancements) - [ ] Additional provider implementations (Storecove, Peppol Connect, etc.) - [ ] PDF generation for Factur-X embedded invoices @@ -257,16 +257,16 @@ use Modules\Invoices\Peppol\Services\PeppolManagementService; $service = app(PeppolManagementService::class); $integration = $service->createIntegration( - companyId: 1, - providerName: 'e_invoice_be', - config: ['base_url' => 'https://api.e-invoice.be'], - apiToken: 'your-api-key' + companyId: 1, + providerName: 'e_invoice_be', + config: ['base_url' => 'https://api.e-invoice.be'], + apiToken: 'your-api-key' ); // Test connection $result = $service->testConnection($integration); if ($result['ok']) { - $integration->update(['enabled' => true]); + $integration->update(['enabled' => true]); } ``` @@ -274,13 +274,13 @@ if ($result['ok']) { ```php $result = $service->validatePeppolId( - customer: $customer, - integration: $integration, - validatedBy: auth()->id() + customer: $customer, + integration: $integration, + validatedBy: auth()->id() ); if ($result['valid']) { - // Customer can receive Peppol invoices + // Customer can receive Peppol invoices } ``` @@ -290,8 +290,8 @@ if ($result['valid']) { $integration = $service->getActiveIntegration($invoice->company_id); if ($integration && $invoice->customer->hasPeppolIdValidated()) { - $service->sendInvoice($invoice, $integration); - // Job is queued, will execute asynchronously + $service->sendInvoice($invoice, $integration); + // Job is queued, will execute asynchronously } ``` @@ -301,9 +301,9 @@ if ($integration && $invoice->customer->hasPeppolIdValidated()) { $transmission = PeppolTransmission::where('invoice_id', $invoice->id)->first(); if ($transmission->status === PeppolTransmission::STATUS_ACCEPTED) { - // Invoice delivered successfully + // Invoice delivered successfully } elseif ($transmission->status === PeppolTransmission::STATUS_DEAD) { - // Manual intervention required + // Manual intervention required } ``` @@ -314,15 +314,15 @@ Add to `app/Console/Kernel.php`: ```php protected function schedule(Schedule $schedule) { - // Poll for status updates every 15 minutes - $schedule->command('peppol:poll-status') - ->everyFifteenMinutes() - ->withoutOverlapping(); - - // Retry failed transmissions every minute - $schedule->command('peppol:retry-failed') - ->everyMinute() - ->withoutOverlapping(); + // Poll for status updates every 15 minutes + $schedule->command('peppol:poll-status') + ->everyFifteenMinutes() + ->withoutOverlapping(); + + // Retry failed transmissions every minute + $schedule->command('peppol:retry-failed') + ->everyMinute() + ->withoutOverlapping(); } ``` @@ -372,51 +372,51 @@ protected function schedule(Schedule $schedule) ``` Modules/Invoices/ -├── Models/ -│ ├── PeppolIntegration.php -│ ├── PeppolTransmission.php -│ └── CustomerPeppolValidationHistory.php -├── Peppol/ -│ ├── Contracts/ -│ │ └── ProviderInterface.php -│ ├── Providers/ -│ │ ├── BaseProvider.php -│ │ ├── ProviderFactory.php -│ │ ├── EInvoiceBe/ -│ │ │ └── EInvoiceBeProvider.php -│ │ └── Storecove/ -│ │ └── StorecoveProvider.php -│ └── Services/ -│ ├── PeppolManagementService.php -│ └── PeppolTransformerService.php -├── Events/Peppol/ -│ ├── PeppolEvent.php (base) -│ ├── PeppolIntegrationCreated.php -│ ├── PeppolIntegrationTested.php -│ ├── PeppolIdValidationCompleted.php -│ ├── PeppolTransmissionCreated.php -│ ├── PeppolTransmissionPrepared.php -│ ├── PeppolTransmissionSent.php -│ ├── PeppolTransmissionFailed.php -│ ├── PeppolAcknowledgementReceived.php -│ └── PeppolTransmissionDead.php -├── Jobs/Peppol/ -│ ├── SendInvoiceToPeppolJob.php -│ ├── PeppolStatusPoller.php -│ └── RetryFailedTransmissions.php -├── Listeners/Peppol/ -│ └── LogPeppolEventToAudit.php -├── Console/Commands/ -│ ├── PollPeppolStatusCommand.php -│ ├── RetryFailedPeppolTransmissionsCommand.php -│ └── TestPeppolIntegrationCommand.php -└── Database/Migrations/ - ├── 2025_10_02_000001_create_peppol_integrations_table.php - ├── 2025_10_02_000002_create_peppol_transmissions_table.php - └── 2025_10_02_000003_create_customer_peppol_validation_history_table.php + Models/ + PeppolIntegration.php + PeppolTransmission.php + CustomerPeppolValidationHistory.php + Peppol/ + Contracts/ + ProviderInterface.php + Providers/ + BaseProvider.php + ProviderFactory.php + EInvoiceBe/ + EInvoiceBeProvider.php + Storecove/ + StorecoveProvider.php + Services/ + PeppolManagementService.php + PeppolTransformerService.php + Events/Peppol/ + PeppolEvent.php (base) + PeppolIntegrationCreated.php + PeppolIntegrationTested.php + PeppolIdValidationCompleted.php + PeppolTransmissionCreated.php + PeppolTransmissionPrepared.php + PeppolTransmissionSent.php + PeppolTransmissionFailed.php + PeppolAcknowledgementReceived.php + PeppolTransmissionDead.php + Jobs/Peppol/ + SendInvoiceToPeppolJob.php + PeppolStatusPoller.php + RetryFailedTransmissions.php + Listeners/Peppol/ + LogPeppolEventToAudit.php + Console/Commands/ + PollPeppolStatusCommand.php + RetryFailedPeppolTransmissionsCommand.php + TestPeppolIntegrationCommand.php + Database/Migrations/ + 2025_10_02_000001_create_peppol_integrations_table.php + 2025_10_02_000002_create_peppol_transmissions_table.php + 2025_10_02_000003_create_customer_peppol_validation_history_table.php Modules/Clients/Database/Migrations/ -└── 2025_10_02_000004_add_peppol_validation_fields_to_relations_table.php + 2025_10_02_000004_add_peppol_validation_fields_to_relations_table.php ``` ## Total Lines of Code diff --git a/PEPPOL_TESTS_SUMMARY.md b/PEPPOL_TESTS_SUMMARY.md index 75c442de5..1f6bc0c6a 100644 --- a/PEPPOL_TESTS_SUMMARY.md +++ b/PEPPOL_TESTS_SUMMARY.md @@ -4,7 +4,7 @@ This document summarizes the comprehensive unit tests generated for the PEPPOL a ## Test Coverage Overview -### ✅ Enum Tests (5 files) +### Enum Tests (5 files) #### 1. PeppolConnectionStatusTest **Location:** `Modules/Invoices/Tests/Unit/Enums/PeppolConnectionStatusTest.php` @@ -19,16 +19,16 @@ This document summarizes the comprehensive unit tests generated for the PEPPOL a - Selection option generation **Key Test Scenarios:** -- ✓ Correct case enumeration -- ✓ Human-readable labels -- ✓ UI color assignments -- ✓ Icon identifiers -- ✓ Value-based instantiation -- ✓ Invalid value handling -- ✓ Try-from with null return -- ✓ Match expression usage - -#### 2. PeppolErrorTypeTest +- Correct case enumeration +- Human-readable labels +- UI color assignments +- Icon identifiers +- Value-based instantiation +- Invalid value handling +- Try-from with null return +- Match expression usage + +#### 2. PeppolErrorTypeTest **Location:** `Modules/Invoices/Tests/Unit/Enums/PeppolErrorTypeTest.php` **Coverage:** @@ -38,10 +38,10 @@ This document summarizes the comprehensive unit tests generated for the PEPPOL a - Upper-case enum values **Key Test Scenarios:** -- ✓ Error type enumeration -- ✓ Transient vs permanent distinction -- ✓ Retry-ability indication through colors -- ✓ Warning vs error icon mapping +- Error type enumeration +- Transient vs permanent distinction +- Retry-ability indication through colors +- Warning vs error icon mapping #### 3. PeppolTransmissionStatusTest **Location:** `Modules/Invoices/Tests/Unit/Enums/PeppolTransmissionStatusTest.php` @@ -54,14 +54,14 @@ This document summarizes the comprehensive unit tests generated for the PEPPOL a - Rejection handling **Key Test Scenarios:** -- ✓ Full status enumeration (9 cases) -- ✓ Final status identification (ACCEPTED, REJECTED, DEAD) -- ✓ Retryable status identification (FAILED, RETRYING) -- ✓ Acknowledgement-waiting status (SENT) -- ✓ Successful transmission lifecycle -- ✓ Failure and retry flow -- ✓ Rejection flow -- ✓ Color and icon appropriateness +- Full status enumeration (9 cases) +- Final status identification (ACCEPTED, REJECTED, DEAD) +- Retryable status identification (FAILED, RETRYING) +- Acknowledgement-waiting status (SENT) +- Successful transmission lifecycle +- Failure and retry flow +- Rejection flow +- Color and icon appropriateness #### 4. PeppolValidationStatusTest **Location:** `Modules/Invoices/Tests/Unit/Enums/PeppolValidationStatusTest.php` @@ -72,11 +72,11 @@ This document summarizes the comprehensive unit tests generated for the PEPPOL a - Visual feedback for validation results **Key Test Scenarios:** -- ✓ Validation status enumeration -- ✓ Success (green) vs error (red) distinction -- ✓ Not found (orange) warning state -- ✓ Appropriate icon selection -- ✓ Clear visual indicators +- Validation status enumeration +- Success (green) vs error (red) distinction +- Not found (orange) warning state +- Appropriate icon selection +- Clear visual indicators #### 5. PeppolEndpointSchemeTest **Location:** `Modules/Invoices/Tests/Unit/Peppol/Enums/PeppolEndpointSchemeTest.php` @@ -88,24 +88,24 @@ This document summarizes the comprehensive unit tests generated for the PEPPOL a - Identifier formatting rules **Key Test Scenarios:** -- ✓ Complete scheme enumeration (17 schemes) -- ✓ Country code mapping (BE→BE_CBE, IT→IT_VAT, etc.) -- ✓ Default to ISO_6523 for unknown countries -- ✓ Belgian CBE validation (10 digits) -- ✓ German VAT validation (DE + 9 digits) -- ✓ French SIRENE validation (9 or 14 digits) -- ✓ Italian VAT validation (IT + 11 digits) -- ✓ Italian Codice Fiscale (16 alphanumeric) -- ✓ Spanish NIF format (letter + digits + letter/digit) -- ✓ Swiss UID with flexible separators -- ✓ UK Companies House alphanumeric -- ✓ GLN (13 digits), DUNS (9 digits) -- ✓ Swedish formatting (adds hyphen) -- ✓ Finnish formatting (adds hyphen) -- ✓ ISO 6523 flexible validation -- ✓ Case-insensitive country handling - -### ✅ Factory Tests (2 files) +- Complete scheme enumeration (17 schemes) +- Country code mapping (BE→BE_CBE, IT→IT_VAT, etc.) +- Default to ISO_6523 for unknown countries +- Belgian CBE validation (10 digits) +- German VAT validation (DE + 9 digits) +- French SIRENE validation (9 or 14 digits) +- Italian VAT validation (IT + 11 digits) +- Italian Codice Fiscale (16 alphanumeric) +- Spanish NIF format (letter + digits + letter/digit) +- Swiss UID with flexible separators +- UK Companies House alphanumeric +- GLN (13 digits), DUNS (9 digits) +- Swedish formatting (adds hyphen) +- Finnish formatting (adds hyphen) +- ISO 6523 flexible validation +- Case-insensitive country handling + +### Factory Tests (2 files) #### 6. FormatHandlerFactoryTest **Location:** `Modules/Invoices/Tests/Unit/Peppol/FormatHandlers/FormatHandlerFactoryTest.php` @@ -118,17 +118,17 @@ This document summarizes the comprehensive unit tests generated for the PEPPOL a - Service container integration **Key Test Scenarios:** -- ✓ PEPPOL BIS 3.0 handler creation -- ✓ UBL 2.1 handler creation -- ✓ UBL 2.4 handler creation (same as 2.1) -- ✓ CII handler creation -- ✓ Exception for unsupported formats -- ✓ hasHandler() validation -- ✓ getRegisteredHandlers() enumeration -- ✓ make() from format string -- ✓ Invalid format string exception -- ✓ Custom handler registration -- ✓ Service container resolution +- PEPPOL BIS 3.0 handler creation +- UBL 2.1 handler creation +- UBL 2.4 handler creation (same as 2.1) +- CII handler creation +- Exception for unsupported formats +- hasHandler() validation +- getRegisteredHandlers() enumeration +- make() from format string +- Invalid format string exception +- Custom handler registration +- Service container resolution #### 7. ProviderFactoryTest **Location:** `Modules/Invoices/Tests/Unit/Peppol/Providers/ProviderFactoryTest.php` @@ -140,21 +140,21 @@ This document summarizes the comprehensive unit tests generated for the PEPPOL a - Integration model passing **Key Test Scenarios:** -- ✓ Automatic provider discovery -- ✓ Friendly provider name generation -- ✓ isSupported() check -- ✓ EInvoiceBe provider creation -- ✓ Storecove provider creation -- ✓ Integration model passing -- ✓ String-based provider creation -- ✓ Unknown provider exception -- ✓ Provider cache functionality -- ✓ Cache clearing -- ✓ Directory-to-snake_case conversion -- ✓ Interface implementation verification -- ✓ Null integration handling - -### ✅ Existing Tests (Already in Repository) +- Automatic provider discovery +- Friendly provider name generation +- isSupported() check +- EInvoiceBe provider creation +- Storecove provider creation +- Integration model passing +- String-based provider creation +- Unknown provider exception +- Provider cache functionality +- Cache clearing +- Directory-to-snake_case conversion +- Interface implementation verification +- Null integration handling + +### Existing Tests (Already in Repository) #### 8. PeppolDocumentFormatTest **Location:** `Modules/Invoices/Tests/Unit/Peppol/Enums/PeppolDocumentFormatTest.php` @@ -209,7 +209,7 @@ This document summarizes the comprehensive unit tests generated for the PEPPOL a ### Coverage by Category: - **Enums:** 5 test files, ~95 test methods -- **Factories:** 2 test files, ~30 test methods +- **Factories:** 2 test files, ~30 test methods - **Actions:** 1 existing file - **HTTP Clients:** 2 existing files - **Services:** 2 existing files @@ -222,10 +222,10 @@ All tests use PHPUnit's `#[DataProvider]` attribute for parameterized testing: #[Test] #[DataProvider('labelProvider')] public function it_provides_correct_labels( - PeppolConnectionStatus $status, - string $expectedLabel + PeppolConnectionStatus $status, + string $expectedLabel ): void { - $this->assertEquals($expectedLabel, $status->label()); + $this->assertEquals($expectedLabel, $status->label()); } ``` @@ -316,26 +316,26 @@ Tests verify: ### Recommended Additional Tests 1. **Model Tests** (Not yet created) - - PeppolIntegration model - - PeppolTransmission model - - CustomerPeppolValidationHistory model + - PeppolIntegration model + - PeppolTransmission model + - CustomerPeppolValidationHistory model 2. **Job Tests** (Not yet created) - - SendInvoiceToPeppolJob - - PeppolStatusPoller - - RetryFailedTransmissions + - SendInvoiceToPeppolJob + - PeppolStatusPoller + - RetryFailedTransmissions 3. **Service Tests** (Partially covered) - - PeppolManagementService - - PeppolTransformerService + - PeppolManagementService + - PeppolTransformerService 4. **Event Tests** (Not yet created) - - All Peppol events with payload validation + - All Peppol events with payload validation 5. **Integration Tests** - - End-to-end transmission flow - - Provider integration - - Database persistence + - End-to-end transmission flow + - Provider integration + - Database persistence ## Test Maintenance Notes @@ -358,10 +358,10 @@ Tests verify: ## Conclusion The test suite provides comprehensive coverage for: -- ✅ All PEPPOL enum types with business logic -- ✅ Factory pattern implementations -- ✅ Validation rules for international identifiers -- ✅ Format handler selection -- ✅ Provider discovery and instantiation +- All PEPPOL enum types with business logic +- Factory pattern implementations +- Validation rules for international identifiers +- Format handler selection +- Provider discovery and instantiation The tests follow Laravel and PHPUnit best practices, use modern PHP 8 attributes, and provide excellent documentation for future maintainers. \ No newline at end of file diff --git a/README.md b/README.md index 0cd526b2f..ad31ba225 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,15 @@ -### Features +# InvoicePlane v2 + +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![PHP Version](https://img.shields.io/badge/PHP-8.2%2B-blue.svg)](https://php.net) +[![Laravel Version](https://img.shields.io/badge/Laravel-12%2B-red.svg)](https://laravel.com) +[![Filament Version](https://img.shields.io/badge/Filament-4.0-orange.svg)](https://filamentphp.com) + +**InvoicePlane v2** is a modern, open-source invoicing and billing application built with Laravel 12, Filament 4, and Livewire. It features a modular architecture, multi-tenancy support, and comprehensive Peppol e-invoicing integration for European businesses. + +--- + +## Features - **Invoice & Quote Management** - Create, send, and track invoices and quotes - **Peppol E-Invoicing** - Send invoices through the European Peppol network (UBL, FatturaPA, ZUGFeRD) @@ -9,70 +20,179 @@ - **Realtime UI** - Built with Livewire for reactive interfaces - **Asynchronous Export System** - Requires queue workers for background processing - **Comprehensive Testing** - PHPUnit tests with 100% coverage goal +- **Internationalization** - Full translation support via Crowdin --- -### Installation +## Requirements + +- PHP 8.2 or higher +- Composer +- Node.js 20+ and Yarn +- MySQL 8.0+ or PostgreSQL 13+ +- Redis (recommended for queue/cache) -To install and run InvoicePlane V2 locally, see the [Installation Guide](.github/INSTALLATION.md). +--- -Quick summary: +## Installation + +To install and run InvoicePlane v2 locally, see the [Installation Guide](.github/INSTALLATION.md). + +### Quick Start ```bash -git clone https://github.com/InvoicePlane/InvoicePlane.git -cd InvoicePlane +# Clone the repository +git clone https://github.com/InvoicePlane/InvoicePlane-v2.git +cd InvoicePlane-v2 + +# Install dependencies composer install +yarn install + +# Setup environment cp .env.example .env php artisan key:generate + +# Setup database php artisan migrate --seed +# Build frontend assets +yarn build + # Start queue worker for export functionality php artisan queue:work ``` **Note:** Export functionality requires a queue worker to be running. For production, configure a queue driver (Redis, database, etc.) and use a process manager like Supervisor. -For detailed steps, see: INSTALLATION.md +For detailed setup instructions, see [INSTALLATION.md](.github/INSTALLATION.md). + +--- + +## Documentation + +- **[Installation Guide](.github/INSTALLATION.md)** - Complete setup instructions +- **[Contributing Guide](.github/CONTRIBUTING.md)** - How to contribute code +- **[Testing Guide](RUNNING_TESTS.md)** - Running and writing tests +- **[Maintenance Guide](.github/MAINTENANCE.md)** - Dependency management and security updates +- **[Seeding Guide](.github/SEEDING.md)** - Database seeding instructions +- **[Upgrade Guide](.github/UPGRADE.md)** - Upgrading from previous versions +- **[Security Policy](.github/SECURITY.md)** - Reporting security vulnerabilities +- **[Peppol Architecture](PEPPOL_ARCHITECTURE.md)** - E-invoicing system details + +--- + +## Development + +### Running Tests + +```bash +# Run all tests +php artisan test + +# Run with coverage +php artisan test --coverage + +# Run specific test suite +php artisan test --testsuite=Unit +php artisan test --testsuite=Feature +``` + +### Code Quality + +```bash +# Format code with Laravel Pint +vendor/bin/pint + +# Run static analysis +vendor/bin/phpstan analyse + +# Run Rector for automated refactoring +vendor/bin/rector process --dry-run +``` +### Building Assets + +```bash +# Development build +yarn dev + +# Production build +yarn build + +# Watch for changes +yarn dev --watch +``` --- -### Contributing +## Contributing We welcome community contributions! To learn how to contribute code, create modules, write tests, or help translate the app: -Read the Contributing Guide +- Read the [Contributing Guide](.github/CONTRIBUTING.md) +- Follow the [Module Checklist](CHECKLIST.md) to avoid duplication +- Review the [Junie Guidelines](.junie/guidelines.md) for coding standards +- Check [Copilot Instructions](.github/copilot-instructions.md) for AI assistance -Follow the Module Checklist to avoid duplication +--- -### Translations -Use Crowdin to help with translations: -https://translations.invoiceplane.com +## Translations ---- +Help translate InvoicePlane v2 into your language using Crowdin: + +**[Join Translation Project →](https://translations.invoiceplane.com)** -Support & Community +Current languages: +- English (default) +- Dutch +- German +- Spanish +- French +- And more... -Discord: https://discord.gg/PPzD2hTrXt +See [TRANSLATIONS.md](.github/TRANSLATIONS.md) for more details. -Forums: https://community.invoiceplane.com +--- -Issue Tracker: https://github.com/InvoicePlane/InvoicePlane/issues +## Support & Community -Documentation Wiki: https://wiki.invoiceplane.com +- **Discord** - [Join our Discord server](https://discord.gg/PPzD2hTrXt) +- **Forums** - [Community discussions](https://community.invoiceplane.com) +- **Issue Tracker** - [Report bugs and request features](https://github.com/InvoicePlane/InvoicePlane-v2/issues) +- **Documentation Wiki** - [Official documentation](https://wiki.invoiceplane.com) --- -### Security +## Security -See SECURITY.md for more info. +If you discover a security vulnerability, please follow our [Security Policy](.github/SECURITY.md) for responsible disclosure. +**Do not** report security vulnerabilities through public GitHub issues. --- -License +## License + +InvoicePlane v2 is open-source software licensed under the **MIT License**. -InvoicePlane V2 is open-source software licensed under the MIT License. The InvoicePlane name and logo are protected trademarks of Kovah.de. + +--- + +## Acknowledgments + +Built with: +- [Laravel](https://laravel.com) - The PHP framework +- [Filament](https://filamentphp.com) - Admin panel framework +- [Livewire](https://livewire.laravel.com) - Reactive frontend +- [Tailwind CSS](https://tailwindcss.com) - Utility-first CSS +- [PHPUnit](https://phpunit.de) - Testing framework + +Special thanks to all our [contributors](https://github.com/InvoicePlane/InvoicePlane-v2/graphs/contributors)! + +--- + +**Made with by the InvoicePlane community** diff --git a/RUNNING_TESTS.md b/RUNNING_TESTS.md index 4251e9542..2e8f058a2 100644 --- a/RUNNING_TESTS.md +++ b/RUNNING_TESTS.md @@ -25,7 +25,7 @@ composer install ./vendor/bin/phpunit Modules/Invoices/Tests/Unit/Enums/ ``` -### Factory Tests +### Factory Tests ```bash ./vendor/bin/phpunit Modules/Invoices/Tests/Unit/Peppol/FormatHandlers/FormatHandlerFactoryTest.php ./vendor/bin/phpunit Modules/Invoices/Tests/Unit/Peppol/Providers/ProviderFactoryTest.php diff --git a/TEST_GENERATION_SUMMARY.md b/TEST_GENERATION_SUMMARY.md index c34efaae2..b795ba590 100644 --- a/TEST_GENERATION_SUMMARY.md +++ b/TEST_GENERATION_SUMMARY.md @@ -1,29 +1,29 @@ # PEPPOL Unit Tests - Generation Summary -## ✅ Tests Successfully Generated +## Tests Successfully Generated ### New Test Files Created: 7 1. **PeppolConnectionStatusTest.php** - Tests connection status enum (3 cases, ~13 tests) - - Location: `Modules/Invoices/Tests/Unit/Enums/` - + - Location: `Modules/Invoices/Tests/Unit/Enums/` + 2. **PeppolErrorTypeTest.php** - Tests error type classification (3 cases, ~10 tests) - - Location: `Modules/Invoices/Tests/Unit/Enums/` + - Location: `Modules/Invoices/Tests/Unit/Enums/` 3. **PeppolTransmissionStatusTest.php** - Tests transmission lifecycle (9 cases, ~25 tests) - - Location: `Modules/Invoices/Tests/Unit/Enums/` + - Location: `Modules/Invoices/Tests/Unit/Enums/` 4. **PeppolValidationStatusTest.php** - Tests validation status (4 cases, ~12 tests) - - Location: `Modules/Invoices/Tests/Unit/Enums/` + - Location: `Modules/Invoices/Tests/Unit/Enums/` 5. **PeppolEndpointSchemeTest.php** - Tests participant identifiers (17 schemes, ~30 tests) - - Location: `Modules/Invoices/Tests/Unit/Peppol/Enums/` + - Location: `Modules/Invoices/Tests/Unit/Peppol/Enums/` 6. **FormatHandlerFactoryTest.php** - Tests format handler factory (~15 tests) - - Location: `Modules/Invoices/Tests/Unit/Peppol/FormatHandlers/` + - Location: `Modules/Invoices/Tests/Unit/Peppol/FormatHandlers/` 7. **ProviderFactoryTest.php** - Tests provider factory (~18 tests) - - Location: `Modules/Invoices/Tests/Unit/Peppol/Providers/` + - Location: `Modules/Invoices/Tests/Unit/Peppol/Providers/` ## Test Coverage Summary @@ -34,12 +34,12 @@ ## Key Features of Generated Tests -✅ Data Provider pattern for parameterized testing -✅ Group tagging with #[Group('peppol')] -✅ Descriptive test names (it_should pattern) -✅ Comprehensive edge case coverage -✅ PHPUnit 10+ attributes (#[Test], #[DataProvider]) -✅ Proper documentation and comments + Data Provider pattern for parameterized testing + Group tagging with #[Group('peppol')] + Descriptive test names (it_should pattern) + Comprehensive edge case coverage + PHPUnit 10+ attributes (#[Test], #[DataProvider]) + Proper documentation and comments ## Running the Tests diff --git a/resources/lang/en/ip.php b/resources/lang/en/ip.php index 64ea142af..59ceca170 100644 --- a/resources/lang/en/ip.php +++ b/resources/lang/en/ip.php @@ -879,4 +879,32 @@ 'duplicate_invoice_number' => 'Duplicate invoice number :number for company :company', 'duplicate_quote_number' => 'Duplicate quote number :number for company :company', #endregion + + #region REPORT BUILDER + 'template_name' => 'Template Name', + 'template_type' => 'Template Type', + 'estimate' => 'Estimate', + 'system_template' => 'System Template', + 'design' => 'Design', + 'clone' => 'Clone', + #endregion + + #region GENERAL + 'format' => 'Format', + 'padding' => 'Padding', + 'system' => 'System', + 'created_at' => 'Created At', + 'customer' => 'Customer', + 'prospect' => 'Prospect', + 'partner' => 'Partner', + 'lead' => 'Lead', + 'gender_unknown' => 'Unknown', + #endregion + + #region TAX RATES + 'tax_rate_type_exclusive' => 'Exclusive', + 'tax_rate_type_inclusive' => 'Inclusive', + 'tax_rate_type_zero' => 'Zero Rated', + 'tax_rate_type_exempt' => 'Exempt', + #endregion ];