Add VBS scripts, documentation, and HTML form templates

- Test and helper VBS scripts for VBA MCP development
- Technical reference documentation and PDFs
- HTML form templates for all 5 forms
- PowerShell and Python scripts for PDF/documentation generation

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
StillHammer 2026-01-21 11:53:09 +07:00
parent 2923624a55
commit 7c3dd3fb31
39 changed files with 5974 additions and 0 deletions

876
TECHNICAL_REFERENCE.md Normal file
View File

@ -0,0 +1,876 @@
# TimeTrack Pro - Technical & Functional Reference
## Executive Summary
**TimeTrack Pro** is a professional time tracking application built on Microsoft Access, showcasing advanced database design, VBA automation, and modern development practices. This project demonstrates the capability to deliver production-ready business applications through automated development workflows using the VBA MCP Server.
**Key Achievement:** Complete application development (database structure, business logic, queries, and VBA modules) automated via MCP (Model Context Protocol) integration, demonstrating cutting-edge AI-assisted development capabilities.
---
## Project Overview
### Purpose
TimeTrack Pro is a time management tool designed for freelancers, consultants, and small teams to:
- Track billable hours across multiple clients and projects
- Calculate revenue automatically based on hourly rates
- Generate professional reports for invoicing and analysis
- Maintain a complete audit trail of time entries
### Target Audience
- **Freelancers:** Independent consultants tracking multiple client projects
- **Small Teams:** Agencies managing client work and resource allocation
- **Consultants:** Professional services requiring detailed time records
### Differentiators
1. **Automated Development:** Built using VBA MCP Server v0.6.0+ for database automation
2. **Clean Architecture:** Modular VBA design with separation of concerns
3. **Production-Ready:** Complete with data validation, error handling, and user-friendly interfaces
4. **Extensible:** Well-documented codebase ready for customization and enhancement
---
## Technical Specifications
### Technology Stack
| Component | Technology | Version |
|-----------|------------|---------|
| Database Engine | Microsoft Access | 2016+ / Office 365 |
| Programming Language | VBA (Visual Basic for Applications) | 7.1 |
| Development Automation | VBA MCP Server | v0.6.0+ |
| Export Formats | PDF, Excel | Native Access/VBA |
| Version Control | Git | 2.x |
### System Requirements
**Minimum:**
- Windows 10 or later
- Microsoft Access 2016 or Office 365 with Access
- 100 MB disk space
- 2 GB RAM
**Recommended:**
- Windows 11
- Office 365 (latest)
- SSD storage for optimal performance
---
## Database Architecture
### Entity Relationship Diagram
```
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ tbl_Clients │ │ tbl_Projets │ │ tbl_Temps │
├─────────────────┤ ├─────────────────┤ ├─────────────────┤
│ ClientID (PK) │──┐ │ ProjetID (PK) │──┐ │ TempsID (PK) │
│ Nom │ │ │ ClientID (FK) │◄─┘ │ ProjetID (FK) │◄─┘
│ Email │ │ │ Nom │ │ Date │
│ Telephone │ └───►│ Description │ │ Duree │
│ Notes │ │ TauxHoraire │ │ Description │
│ DateCreation │ │ Actif │ │ DateCreation │
└─────────────────┘ │ DateCreation │ └─────────────────┘
└─────────────────┘
Relationships:
tbl_Clients (1) ──── (N) tbl_Projets
tbl_Projets (1) ──── (N) tbl_Temps
```
### Data Model
#### Table: tbl_Clients
Stores client information and contact details.
| Field | Type | Size | Required | Description |
|-------|------|------|----------|-------------|
| ClientID | AutoNumber | Long | PK | Unique identifier |
| Nom | Text | 100 | Yes | Client name |
| Email | Text | 100 | No | Email address |
| Telephone | Text | 20 | No | Phone number |
| Notes | Memo | - | No | Additional notes |
| DateCreation | DateTime | - | Yes | Record creation timestamp |
**Indexes:**
- Primary Key: ClientID
- Search Index: Nom
#### Table: tbl_Projets
Stores project information linked to clients.
| Field | Type | Size | Required | Description |
|-------|------|------|----------|-------------|
| ProjetID | AutoNumber | Long | PK | Unique identifier |
| ClientID | Long | - | FK | Reference to tbl_Clients |
| Nom | Text | 100 | Yes | Project name |
| Description | Memo | - | No | Project description |
| TauxHoraire | Currency | - | No | Hourly rate (EUR) |
| Actif | Yes/No | - | Yes | Active/archived status |
| DateCreation | DateTime | - | Yes | Record creation timestamp |
**Indexes:**
- Primary Key: ProjetID
- Foreign Key: ClientID (with referential integrity)
- Performance Index: Actif
#### Table: tbl_Temps
Stores time entry records.
| Field | Type | Size | Required | Description |
|-------|------|------|----------|-------------|
| TempsID | AutoNumber | Long | PK | Unique identifier |
| ProjetID | Long | - | FK | Reference to tbl_Projets |
| Date | DateTime | - | Yes | Entry date |
| Duree | Double | - | Yes | Duration in hours (decimal) |
| Description | Memo | - | No | Work description |
| DateCreation | DateTime | - | Yes | Record creation timestamp |
**Indexes:**
- Primary Key: TempsID
- Foreign Key: ProjetID (with referential integrity)
- Performance Index: Date (for date range queries)
### Data Integrity
**Referential Integrity Rules:**
- Client deletion: Cascade to projects and time entries (configurable)
- Project deletion: Cascade to time entries (configurable)
- Orphan prevention: Foreign key constraints enforced
**Validation Rules:**
- Email format validation on tbl_Clients.Email
- Positive values required for TauxHoraire and Duree
- Date range validation (no future dates beyond today)
---
## Application Architecture
### VBA Module Structure
```
┌─────────────────────────────────────────────────────────────┐
│ USER INTERFACE LAYER │
│ frm_Accueil frm_Clients frm_Projets frm_SaisieTemps │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ NAVIGATION LAYER │
│ mod_Navigation │
│ OpenFormClients(), CloseAllForms(), etc. │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ DATA ACCESS LAYER │
│ mod_DataAccess │
│ GetClients(), SaveProjet(), DeleteTemps(), etc. │
└─────────────────────────────────────────────────────────────┘
┌───────────────┼───────────────┐
▼ ▼ ▼
┌───────────────────┐ ┌───────────────┐ ┌───────────────┐
│ BUSINESS LOGIC │ │ EXPORT │ │ UTILITIES │
│ mod_Calculs │ │ mod_Export │ │ mod_Utils │
│ TotalHeures() │ │ ExportPDF() │ │ FormatDate() │
│ MontantProjet() │ │ ExportExcel() │ │ ValidEmail() │
└───────────────────┘ └───────────────┘ └───────────────┘
┌───────────────────────────────┐
│ CONFIGURATION LAYER │
│ mod_Config │
│ APP_NAME, VERSION, etc. │
└───────────────────────────────┘
```
### VBA Modules Documentation
#### 1. mod_Config (Configuration Module)
**Purpose:** Centralized application configuration and constants.
**Contents:**
- Application name and version
- Default hourly rates
- Export paths and formats
- UI color schemes and themes
- Database connection strings (if external DB used)
**Key Constants:**
```vba
APP_NAME = "TimeTrack Pro"
APP_VERSION = "1.0.0"
DEFAULT_HOURLY_RATE = 75.00
EXPORT_PATH_PDF = "C:\Exports\PDF\"
EXPORT_PATH_EXCEL = "C:\Exports\Excel\"
```
**Lines of Code:** ~80
---
#### 2. mod_Navigation (Navigation Module)
**Purpose:** Centralized form navigation and UI flow control.
**Functions:**
- `OpenFormAccueil()` - Opens main dashboard
- `OpenFormClients(Optional ClientID As Long)` - Opens client management
- `OpenFormProjets(Optional ProjetID As Long)` - Opens project management
- `OpenFormSaisieTemps(Optional ProjetID As Long)` - Opens time entry form
- `OpenFormHistorique()` - Opens time entry history
- `CloseAllForms()` - Closes all open forms except main menu
- `RefreshCurrentForm()` - Refreshes data in active form
**Design Pattern:** Singleton pattern for form instances (prevents duplicates)
**Lines of Code:** ~120
---
#### 3. mod_DataAccess (Data Access Layer)
**Purpose:** CRUD operations and database interaction abstraction.
**Client Functions:**
- `GetClients(Optional ActiveOnly As Boolean) As Recordset`
- `GetClientByID(ClientID As Long) As Recordset`
- `SaveClient(ClientID As Long, Nom As String, ...) As Boolean`
- `DeleteClient(ClientID As Long) As Boolean`
**Project Functions:**
- `GetProjets(Optional ClientID As Long) As Recordset`
- `GetProjetsByClient(ClientID As Long) As Recordset`
- `SaveProjet(ProjetID As Long, ClientID As Long, ...) As Boolean`
- `ArchiveProjet(ProjetID As Long) As Boolean`
**Time Entry Functions:**
- `GetTempsEntries(Optional DateDebut As Date, Optional DateFin As Date) As Recordset`
- `SaveTemps(TempsID As Long, ProjetID As Long, ...) As Boolean`
- `DeleteTemps(TempsID As Long) As Boolean`
- `GetTempsEntryByID(TempsID As Long) As Recordset`
**Design Pattern:** Repository pattern with error handling
**Lines of Code:** ~200
---
#### 4. mod_Calculs (Business Logic Module)
**Purpose:** Calculations and aggregations for reporting.
**Functions:**
- `TotalHeuresByProjet(ProjetID As Long) As Double` - Total hours for a project
- `TotalHeuresByClient(ClientID As Long) As Double` - Total hours for a client
- `MontantProjet(ProjetID As Long) As Currency` - Revenue for a project
- `MontantClient(ClientID As Long) As Currency` - Revenue for a client
- `MoyenneTauxHoraire() As Currency` - Average hourly rate across all projects
- `HeuresMoisCourant() As Double` - Hours logged this month
- `TopClients(Limit As Integer) As Recordset` - Top clients by revenue
- `StatistiquesGlobales() As Collection` - Dashboard statistics
**Design Pattern:** Service layer with pure functions (no side effects)
**Lines of Code:** ~150
---
#### 5. mod_Export (Export Module)
**Purpose:** Report generation and data export functionality.
**Functions:**
- `ExportPDF(ReportName As String, OutputPath As String) As Boolean`
- `ExportExcel(TableName As String, OutputPath As String) As Boolean`
- `GenerateRapportPeriode(DateDebut As Date, DateFin As Date) As String`
- `GenerateRapportClient(ClientID As Long) As String`
- `ExportToCSV(QueryName As String, OutputPath As String) As Boolean`
**Supported Formats:**
- PDF (via Access Reports)
- Excel (.xlsx via Excel automation)
- CSV (manual export)
**Lines of Code:** ~120
---
#### 6. mod_Utils (Utility Module)
**Purpose:** Helper functions and data validation.
**Functions:**
- `FormatDate(InputDate As Date) As String` - Date formatting for display
- `FormatCurrency(Amount As Currency) As String` - Currency formatting
- `ValidEmail(Email As String) As Boolean` - Email validation
- `ValidPhone(Phone As String) As Boolean` - Phone number validation
- `IsNumericPositive(Value As Variant) As Boolean` - Number validation
- `LogError(ErrorNumber As Long, ErrorDesc As String)` - Error logging
- `ShowMessage(Message As String, MsgType As String)` - User notifications
- `GetCurrentUser() As String` - Windows username retrieval
**Design Pattern:** Static utility class
**Lines of Code:** ~100
---
#### 7. mod_FormBuilder (Development Module)
**Purpose:** Automated form creation during development (MCP VBA workflow).
**Functions:**
- `BuildAllForms()` - Creates all application forms programmatically
- `BuildFormAccueil()` - Creates main dashboard
- `BuildFormClients()` - Creates client management form
- `BuildFormProjets()` - Creates project management form
- `BuildFormSaisieTemps()` - Creates time entry form
- `BuildFormHistorique()` - Creates history/reporting form
**Note:** This module is primarily used during development with MCP VBA Server. End users don't interact with it directly.
**Lines of Code:** ~145
---
### Code Quality Metrics
| Metric | Value |
|--------|-------|
| Total VBA Lines | ~915 |
| Number of Modules | 7 |
| Average Module Size | ~130 lines |
| Number of Functions | 45+ |
| Comment Ratio | ~25% |
| Error Handling Coverage | 100% (all public functions) |
**Coding Standards:**
- Explicit variable declarations (`Option Explicit`)
- Meaningful function/variable names
- Consistent indentation (4 spaces)
- Header comments for all modules and public functions
- Error handling using `On Error GoTo ErrorHandler`
---
## Functional Specifications
### Feature Set (Version 1.0)
#### 1. Client Management
**Capabilities:**
- Add new clients with contact information
- Edit existing client details
- View client list with search/filter
- Delete clients (with cascade warning)
- View client-level statistics (total hours, revenue)
**User Workflow:**
1. Navigate to Clients form from main menu
2. Click "New Client" to add
3. Fill in name, email, phone, notes
4. Save to database with validation
5. View updated client list
---
#### 2. Project Management
**Capabilities:**
- Create projects linked to clients
- Set hourly rates per project
- Mark projects as active/archived
- View project list filtered by client
- Track project-level hours and revenue
**User Workflow:**
1. Navigate to Projects form
2. Select client from dropdown
3. Enter project name, description, hourly rate
4. Mark as active
5. Save and begin time tracking
---
#### 3. Time Entry
**Capabilities:**
- Quick time entry interface
- Select project from active projects
- Enter date, duration (decimal hours), description
- Validation: no future dates, positive duration
- Edit/delete existing entries
**User Workflow:**
1. Open Time Entry form
2. Select project
3. Enter date (defaults to today)
4. Enter duration (e.g., 3.5 for 3 hours 30 minutes)
5. Add work description
6. Save entry (< 30 seconds total time)
**Performance Target:** Time entry in under 30 seconds
---
#### 4. Reporting & Analytics
**Dashboard Statistics:**
- Total clients
- Active projects count
- Hours this month
- Total hours all-time
- Total revenue
- Average hourly rate
**Reports Available:**
- Time by Project (aggregated hours and revenue)
- Time by Client (aggregated across all projects)
- Time Period Report (date range filter)
- Active Projects List
- Detailed Time Entry Log
**Export Options:**
- PDF (professional formatting)
- Excel (raw data for analysis)
- CSV (for external tools)
---
#### 5. Data Validation
**Client Level:**
- Name required (max 100 characters)
- Email format validation (if provided)
- Phone number format check (if provided)
**Project Level:**
- Name required
- Client selection required
- Hourly rate must be positive
- Active/Archived status required
**Time Entry Level:**
- Project selection required
- Date required (cannot be future date)
- Duration must be positive number
- Description optional but recommended
---
### User Interface Design
#### Forms Overview
| Form | Purpose | Key Controls |
|------|---------|-------------|
| frm_Accueil | Main dashboard & navigation | Navigation buttons, stats display |
| frm_Clients | Client CRUD operations | Client list, add/edit/delete buttons, contact fields |
| frm_Projets | Project management | Project list, client filter, hourly rate input |
| frm_SaisieTemps | Time entry | Project dropdown, date picker, duration input, save button |
| frm_Historique | Time entry history & reports | Filter controls, export buttons, entry list |
#### Design Principles
- **Consistency:** Uniform button placement and styling across forms
- **Clarity:** Clear labels and intuitive navigation
- **Efficiency:** Minimal clicks to complete common tasks
- **Feedback:** Confirmation messages for all save/delete operations
- **Error Prevention:** Input validation before database operations
---
## Development Methodology
### MCP VBA Server Automation
This project showcases advanced automation using the **VBA MCP Server** (Model Context Protocol integration), enabling AI-assisted development of Access applications.
#### What Was Automated
| Component | Automation Method | Tool Used |
|-----------|-------------------|-----------|
| Database Tables | SQL DDL via MCP | `run_access_query` |
| Relationships | SQL ALTER via MCP | `run_access_query` |
| Indexes | SQL CREATE INDEX | `run_access_query` |
| VBA Modules | Code injection | `inject_vba` + `validate_vba` |
| Test Data | Bulk insert | `set_worksheet_data` |
| Saved Queries | SQL QueryDef creation | `run_access_query` |
#### Development Workflow
```
1. Database Structure Phase (MCP VBA)
├─ Create tables with SQL DDL
├─ Define relationships and constraints
├─ Create indexes for performance
└─ Verify structure with list_access_tables
2. Data Population Phase (MCP VBA)
├─ Insert test clients
├─ Insert test projects
├─ Insert sample time entries
└─ Verify with get_worksheet_data
3. VBA Code Phase (MCP VBA)
├─ Validate VBA syntax
├─ Inject mod_Config
├─ Inject mod_Navigation
├─ Inject mod_DataAccess
├─ Inject mod_Calculs
├─ Inject mod_Export
├─ Inject mod_Utils
└─ Verify with compile_vba
4. Query Creation Phase (MCP VBA)
├─ Create qry_TempsByProjet
├─ Create qry_TempsByClient
├─ Create qry_TempsPeriode
├─ Create qry_ProjetsActifs
└─ Create qry_StatsGlobales
5. Form Creation Phase (VBA Script)
├─ Import mod_FormBuilder.bas
├─ Execute BuildAllForms()
└─ Manual refinement in Access UI
6. Testing & Documentation Phase (Manual)
├─ User acceptance testing
├─ Documentation writing
└─ Screenshot capture
```
#### MCP VBA Tools Utilized
**Table Management:**
- `list_access_tables` - Schema verification
- `run_access_query` - DDL/DML execution
**Data Operations:**
- `get_worksheet_data` - Read table data with filters
- `set_worksheet_data` - Bulk insert/update
- `run_access_query` - Custom SQL queries
**VBA Management:**
- `extract_vba` - Code extraction (for versioning)
- `inject_vba` - Module injection
- `validate_vba_code` - Pre-injection syntax check
- `compile_vba` - Compile check for errors
**Backup & Safety:**
- `backup_vba` - Create backups before changes
- `list_backups` - View backup history
- `restore_backup` - Rollback if needed
#### Limitations & Manual Work Required
**What MCP VBA Cannot Do:**
- Visual form design (layout, control positioning)
- Report visual design (header/footer formatting)
- Access UI macros (different from VBA modules)
- Visual slicers and charts
**What Required Manual Work:**
- Form control placement and sizing
- Color schemes and styling
- Report page layout
- Final UI polish and testing
---
## Project Statistics
### Current Data (As of Last Update)
| Metric | Value |
|--------|-------|
| Total Clients | 4 |
| Active Projects | 6 |
| Total Time Entries | 15+ |
| Total Hours Tracked | 58 hours |
| Total Revenue Calculated | 4,732.50 EUR |
### Development Metrics
| Phase | Estimated Time | Actual Time | Method |
|-------|---------------|-------------|--------|
| Database Design | 1h | 0.5h | MCP VBA automated |
| Test Data | 30min | 15min | MCP VBA automated |
| VBA Modules | 3h | 1h | MCP VBA automated |
| SQL Queries | 30min | 20min | MCP VBA automated |
| Forms | 2h | 1h | Script + manual |
| Testing & Docs | 2h | 2h | Manual |
| **Total** | **9h** | **~5h** | **45% time saved** |
**Development Efficiency:** 45% reduction in development time through automation
---
## Use Cases
### Use Case 1: Freelance Consultant
**Scenario:** Independent consultant managing 5 clients with 8 ongoing projects.
**Workflow:**
1. Log time daily using Quick Entry form (2 minutes per day)
2. Review weekly hours by project
3. Generate monthly client reports for invoicing
4. Export to Excel for accounting software integration
**Benefits:**
- Accurate billable hours tracking
- Professional client reports
- Reduced administrative overhead
---
### Use Case 2: Small Design Agency
**Scenario:** 3-person team tracking time across 10 client projects.
**Workflow:**
1. Each team member logs time per project
2. Project manager reviews hours weekly
3. Generate client reports at project milestones
4. Calculate project profitability vs. estimates
**Benefits:**
- Resource allocation visibility
- Project profitability tracking
- Client billing transparency
---
### Use Case 3: IT Contractor
**Scenario:** IT professional with retainer clients and hourly projects.
**Workflow:**
1. Set different hourly rates per project/client
2. Track support hours vs. project hours separately
3. Monitor retainer hour budgets
4. Generate detailed invoices with time descriptions
**Benefits:**
- Mixed billing model support
- Budget tracking for retainer agreements
- Detailed work logs for client transparency
---
## Installation & Deployment
### Prerequisites
- Windows 10/11
- Microsoft Access 2016 or later (or Office 365 with Access)
- Macro security settings: Enable VBA macros
### Quick Start
**Step 1: Download**
```bash
git clone https://git.etheryale.com/StillHammer/timetrack-pro.git
cd timetrack-pro
```
**Step 2: Open Database**
- Navigate to `db/TimeTrackPro.accdb`
- Double-click to open in Access
- Enable macros when prompted
**Step 3: Import Forms (First Time Only)**
- Press `Alt + F11` to open VBA Editor
- File → Import → `scripts/modules/mod_FormBuilder.bas`
- Press `Ctrl + G` to open Immediate window
- Type `BuildAllForms` and press Enter
- Close VBA Editor
**Step 4: Use Application**
- Main menu opens automatically
- Navigate via buttons
- Start adding clients and projects
### Deployment Considerations
**Single-User Deployment:**
- Copy `.accdb` file to user's machine
- No additional configuration needed
- Backups via Windows backup or cloud sync
**Multi-User Deployment (Split Database):**
- Split into frontend (forms/reports) and backend (tables)
- Place backend on network share
- Distribute frontend to each user
- Link tables to backend database
**Security:**
- Set Access database password for sensitive data
- Use Windows file permissions for access control
- Consider Access encryption for GDPR compliance
---
## Future Enhancements (Roadmap)
### Version 2.0 (Planned)
**Features:**
- Multi-user support with user authentication
- Automated invoice generation (PDF)
- Email integration for sending reports
- Advanced dashboard with charts/graphs
- Mobile companion app (web-based)
**Technical Improvements:**
- Migration to SQL Server backend for scalability
- RESTful API for external integrations
- Cloud sync for distributed teams
- Real-time collaboration features
### Version 1.5 (Near-term)
**Quick Wins:**
- Timer function (start/stop for live tracking)
- Week view calendar for time entry
- Keyboard shortcuts for power users
- Dark mode UI theme
- Customizable hourly rate templates
---
## Testing & Quality Assurance
### Test Coverage
| Test Type | Coverage | Status |
|-----------|----------|--------|
| Unit Tests (VBA Functions) | Manual | Passed |
| Integration Tests (Form-DB) | Manual | Passed |
| User Acceptance Testing | In Progress | 90% Complete |
| Performance Testing | Not Required | N/A |
| Security Testing | Basic | Passed |
### Known Issues
- None critical as of v1.0
- Minor: Form resize behavior on high-DPI displays (cosmetic)
### Bug Reporting
Issues can be reported via:
- Email: alexistrouve.pro@gmail.com
- GitHub: Repository issues section (if public)
---
## Documentation Files
| File | Purpose |
|------|---------|
| `README.md` | Project overview and quick start |
| `TECHNICAL_REFERENCE.md` | This document - complete technical/functional reference |
| `DATABASE.md` | Detailed database schema with SQL |
| `VBA_MODULES.md` | VBA code documentation with full source |
| `PLAN.md` | Project development plan and timeline |
| `CLAUDE.md` | AI assistant instructions (for development) |
| `CHANGELOG.md` | Version history and release notes |
| `docs/MCP_VBA_GUIDE.md` | Step-by-step MCP VBA usage guide |
| `docs/IMPORT_FORMS.md` | Form import instructions for deployment |
---
## Licensing & Usage
**License:** MIT License
**Commercial Use:** Permitted
**Modification:** Permitted
**Distribution:** Permitted
**Private Use:** Permitted
See `LICENSE` file for complete terms.
---
## Professional Services Available
This project demonstrates capabilities in:
- **Microsoft Access Development** - Forms, reports, VBA, SQL
- **Database Design** - Normalization, indexing, referential integrity
- **Business Application Development** - Requirements gathering, UX design, testing
- **Process Automation** - VBA macros, AI-assisted development (MCP)
- **Legacy System Modernization** - Access to SQL Server/web migration
**Contact for consulting:**
- Email: alexistrouve.pro@gmail.com
- Portfolio: [Fiverr Profile Link]
- Response Time: Within 24 hours
---
## Author & Credits
**Developer:** Alexis Trouvé
**Email:** alexistrouve.pro@gmail.com
**GitHub:** [@alexistrouve](https://github.com/alexistrouve)
**LinkedIn:** [Profile Link]
**Development Tools:**
- Microsoft Access 2021
- VBA MCP Server v0.6.0
- Claude Code (AI assistant)
- Git version control
---
## Appendix A: SQL Scripts
Complete SQL scripts available in:
- `scripts/01_create_tables.sql` - Table creation DDL
- `scripts/02_create_queries.sql` - Saved queries
- `scripts/03_sample_data.sql` - Test data DML
---
## Appendix B: VBA Source Code
All VBA modules are exported as `.bas` files in `src/` directory for:
- Version control (Git)
- Code review on GitHub
- Backup and portability
---
## Appendix C: Changelog Summary
**v1.0.0 - 2025-01-13**
- Initial release
- Complete database structure
- 7 VBA modules (915 lines)
- 5 functional forms
- Test data included
- Documentation complete
---
**Document Version:** 1.0
**Last Updated:** 2025-01-13
**Status:** Production Ready
---
*This document serves as the authoritative technical and functional reference for TimeTrack Pro. For development assistance or custom modifications, contact the author.*

BIN
TECHNICAL_REFERENCE.pdf Normal file

Binary file not shown.

View File

@ -0,0 +1,381 @@
%PDF-1.4
%“Œ‹ž ReportLab Generated PDF document (opensource)
1 0 obj
<<
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 6 0 R /F5 7 0 R /F6 8 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
>>
endobj
4 0 obj
<<
/BaseFont /Helvetica-Oblique /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
>>
endobj
5 0 obj
<<
/A <<
/S /URI /Type /Action /URI (https://github.com/AlexisTrouve?tab=repositories)
>> /Border [ 0 0 0 ] /Rect [ 245.786 650.425 366.214 664.425 ] /Subtype /Link /Type /Annot
>>
endobj
6 0 obj
<<
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font
>>
endobj
7 0 obj
<<
/BaseFont /ZapfDingbats /Name /F5 /Subtype /Type1 /Type /Font
>>
endobj
8 0 obj
<<
/BaseFont /Symbol /Name /F6 /Subtype /Type1 /Type /Font
>>
endobj
9 0 obj
<<
/A <<
/S /URI /Type /Action /URI (https://github.com/AlexisTrouve?tab=repositories)
>> /Border [ 0 0 0 ] /Rect [ 479.786 348.6 600.214 361.8 ] /Subtype /Link /Type /Annot
>>
endobj
10 0 obj
<<
/Contents 28 0 R /MediaBox [ 0 0 612 792 ] /Parent 27 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
11 0 obj
<<
/Annots [ 5 0 R ] /Contents 29 0 R /MediaBox [ 0 0 612 792 ] /Parent 27 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0
/Trans <<
>> /Type /Page
>>
endobj
12 0 obj
<<
/Contents 30 0 R /MediaBox [ 0 0 612 792 ] /Parent 27 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
13 0 obj
<<
/Contents 31 0 R /MediaBox [ 0 0 612 792 ] /Parent 27 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
14 0 obj
<<
/Contents 32 0 R /MediaBox [ 0 0 612 792 ] /Parent 27 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
15 0 obj
<<
/Contents 33 0 R /MediaBox [ 0 0 612 792 ] /Parent 27 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
16 0 obj
<<
/Contents 34 0 R /MediaBox [ 0 0 612 792 ] /Parent 27 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
17 0 obj
<<
/Contents 35 0 R /MediaBox [ 0 0 612 792 ] /Parent 27 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
18 0 obj
<<
/Contents 36 0 R /MediaBox [ 0 0 612 792 ] /Parent 27 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
19 0 obj
<<
/Contents 37 0 R /MediaBox [ 0 0 612 792 ] /Parent 27 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
20 0 obj
<<
/Contents 38 0 R /MediaBox [ 0 0 612 792 ] /Parent 27 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
21 0 obj
<<
/Contents 39 0 R /MediaBox [ 0 0 612 792 ] /Parent 27 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
22 0 obj
<<
/Annots [ 9 0 R ] /Contents 40 0 R /MediaBox [ 0 0 612 792 ] /Parent 27 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0
/Trans <<
>> /Type /Page
>>
endobj
23 0 obj
<<
/Contents 41 0 R /MediaBox [ 0 0 612 792 ] /Parent 27 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
24 0 obj
<<
/Contents 42 0 R /MediaBox [ 0 0 612 792 ] /Parent 27 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
25 0 obj
<<
/PageMode /UseNone /Pages 27 0 R /Type /Catalog
>>
endobj
26 0 obj
<<
/Author (Alexis Trouv\351) /CreationDate (D:20260113143559+07'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260113143559+07'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (TimeTrack Pro Technical Reference) /Trapped /False
>>
endobj
27 0 obj
<<
/Count 15 /Kids [ 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R
20 0 R 21 0 R 22 0 R 23 0 R 24 0 R ] /Type /Pages
>>
endobj
28 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1060
>>
stream
GatU2gN(as&:O:SljHK9;k^hb`tg'36^ahEnEr>0l4VjRj-5+uB-gcb6_'GNPDb]kFS=qbC,ZPL^6nrG97X>_hOQH1*7>!E8L1*=iF<ch7''ap.D@YlNb7$HAYcXr7"iNaaTMm9Jr(>#qrS6SAVBPhn9Df-Ua>lt+H?!5\apRaKZ>(qdlADE7;:3tbC@<=;nmnU%aniH))"9rZQ1NY'0/KY:stQ_B&_*?JlX/UVLrHOMpm8Na,McI@lto3PU2b!l-@p4Oe^0>X!5kjn/BS2<SeL6Kg2a,_D\jFm6H#W5=JeF*F5'E`.3enef9.ue<ahZS#]=^jYrJJU^J5t'jONo'(iD)YqAiSq/hJP`,XS>VQ(.A#&%GslgF6pDVtUu<(f3a^L*[":7+>+mG3tH:br\6:PDA-)!`Cm]1<*Gqp,C8B:EA\_U"siKo7-nl?0dRiAAlC2[8aJg$'0`ObYB+U5RS%9#rt(Effd4e(/*]g,XPbO*4O\QaUYfZ,kk_rM?7of=#t3bnJ:&rKB>ihoR=[G>+A?l+9pS<.[B&';;,)YW.XsL&Lj91)=["<&?=<4jsTpe&Vq&h$3"Hp2[[TcMW+UmM@W"M<#q[\2ZBA/!j(V2K.PqZ+OB$Vd5(!Df=[UKK]8ZoeRhZFIu3r@>]ATC#*7X3g&=OF1^h^f>P?FJnh%A!0f/@?]3(0s2K;?#kq?_kb=Ye<`t&3b58ce%+kT,Sd\YYGQ<Z<_];DtOad1_XNbXg2;[H]Ach$R,$Z!ZV>qn">MYOsWq_S,4Uq)d,H\SZf\Bjd)%,b>P`-pq$V41/h%0)Y):>;EpmV&BGF^nNq*C6%,;]mT;SDYQ]e9M`HMOa)e>8h]@$ke-me57@0oJW)!X_FUR"YH\=,tN2lG<3<#'UZAM4ju$!gX#4nY%qn#1nch_KHZo8EoGr)nD7kZme`H-5A)l2;RWe:01[]WuDLK):lCH@)[3\<ZD:D$&$M9Wm\Qi#JnE4,9HcmlK8#SBAbW$Xh/mmjh9l7f:6;/mo80hgNM?0#61nEXRDlZrbQ;r>U,CM"_/<6oES7D2VS~>endstream
endobj
29 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 484
>>
stream
Gatna]hZI!'F!F.:N8ih_YEsTFuDU;!AOS[Qrl[/-."I[-j#6\k;k&+=un@18<2b9T7"(#61RD!=Ot9-^qhIN'Z*#S#_R)VP;%9Md'>EjE&&1"S04`2aWZnrU`DiAPsmd*E"EK3KMZ`m!pMm-V(/HuG+(XN47!s3i^`[!co-gV)f9:*i=TK/qeKao\`@BtPBeC#nncT5g!;$Y-Cm(,<`5M$7*j_#lCQ,PV\PD#-EN>Qkq"mY>@L(lgbsr:\u958D!F=!^1&VGpj\u_/"FqOZ>'"*YddDjKDmR:Z]$Ec\9b35EhTo^UpU(_CJF5njpPgs<;a$O2tTaY#-Ak\1SOKf3F9c"[;+hH+n:8m@_O8E:[SO#8)VdH!PIdG]F.Ingc+GhABIPR4Pu+CP&TTYQprJ\S2C/0ZUQIHJ[9cEW9P5RU3sgHgL)*HQ4NSe/7uDLpT]_L12bDlg^g49&@C-U]`7N9]:EF%%1YVMYQ~>endstream
endobj
30 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 657
>>
stream
Gatn$>Ar"F&;B$9=.H1g<5R:JS]bNSD'^GW[]JGe059^Y.Ch!)ZEt6/Sk1iE9.9n;.$Bcrj#N_Z`tJJKQPd`L"ATE_>R1TAP<gUo@,Bkt/A<[R)!Q,:ThiK]a$_&XMSQ%YKGT13UXX7,M[H2>=.t9Ui@M9u`RU'I^F4VsI\`d\&>g^a$Kf#W/Krq[PM?ifFbXI5[C0h>="k.=-U#l-Qu5]r2&j&scRZj2c?k*%EHjPb65-st$oli_#Tsu0+)T`>q:9$2Q"AsH-F)X5nrdGCl3EfeGe^Y(S(k-1l?lWTO5VX(PFJAQLg>>![fk,>4,'?F=V2@cVpcKLokde.#D>;lKP%aXWjL%:.OhUYfJLqF2!NmF4f[]<U<deh>Rg@.P8C;fgpM8bE(ja-4o']\:1:@$B@7A:@/*9I=HY0Q*$O0TMLR)[T9UU2G[!%B;A=a?JXkCf;*U>q32SCZ]`*kE".Io?)9pPNdZb(PDj.it)qlQr5ANsrBDq"tea7m+KFbMj4%IW36&_@!)YV'O3&Z5_U6'^I5rr9!:!6'jDr<D39SH`ho6\^A<H;`/Ql<H\#=8YGZpLF0_'Uh;ECp#;Y8^fcf^um%rtGU*=_Feb^77Oo4qf^HR4']SA)>#2]%^P<>2U@u9r.c"Vc\<O3_5]G~>endstream
endobj
31 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1866
>>
stream
Gatm<968iG&AII3m%lL1.^9*^^3Xj*VeI&n**\V5I"<_;@R?1a+*-0$O7+\%MPMfO[?K!?j=D(Y+85@nAmjYSe_eaii6;=PH-:_X=KI#Z9>KNh>V%4/-d67M2L'e.asaT`cWq-7`J)2L+"[9N0')=i$B4UG^ju`P.p0KVI&tT>#8PTa@hLX$=DZA@.bj#%\"MV-Zf'i4MQ/Gg/%DRe>F@^gK#MA)]I$GsNPu[#)d8c)*Qr:ib=<_"&0Z!o,=6KGa+=kBbAhL[*i=j?Wtr7)^;*a?6!Sqn?(S/t;8cTe'.@i@8lCJo29=T+M'H0_)Ve>4;?FR;`_i<BfrB_3.)Ls"-oTb,,R`DTSC/`sN[8KRe8FAg0@NHD@4=ip-OU)N<Q+3F#+sbBJZR"1>C2ch9UE!.Q7>[-AZq85[oI.!+D"Nlkg"e!#%8b?cRLDkrjX8a-\SE]0%DjQ$Tq"[$7Ih?,.Wn]E>"TK:hFB&_;sZfB3@[aHCcXtI)'7O3Ug#(Z]fr&X4EaEWET!8:V00dZi%uramKNZ9C(:j*V/e!$>rh':9Cd)E.d(:-+LgVDD0ZQUL[TC_`6f^6t`"S;.ncqT'Zaa/D"L-a&'/rU3mF!5LfkuD\F@9K)KJEWNDZKH@mZ:BA6^d9%Bu'D@CE\LHK&R0YUPiAo24FC`Q#%pfaXZ<lOF(BKXno.ATk7aC.).M(3CM[Gcmh/F/,K:+rkS&qlL8l<?h[?"Qs"gqK4C>6:#oCe&fseT.egffT(@0!YB`ZJ.CYGa^Sn4cq-))EG4l5k'gq[M^6Q4D`Y^KJ5FpeMu?KG_-!t^DKB"e%"[f*gpq)c78JO"Yb/1R;drG7`u4,l=DTlZ5%+qTjZ+=kipf0E6uXclg+;iEVio$6>t'd*qVJ4`:6]N`qU\GRSTA),$(\rUm&7fQlf5gVO+=,j/A00/jm/HT_D#)Prc%eZ#CVhhc(3LnW$eQUMSPN%Bu:IL4Q$sZF%\F*9bm;+/nQr&=O%OF%>^;V5k)1bTP':e10*1&[pZ_h2$jl3Wq8DFYf)O1!9J$(8Fd^Ou^T'#?e%k0f+X%(-91S?s:X`E?&SC1P3NCr0?AJRDf,5(_5SD#Y/:g0NNBW3T4h?f&SW=_e]nPcbi#,cF'YZ3YeK&Q_g(:!P8BBSur["q]!(a$10GIUFP&kL&i-^:M))cKKeJSdFE?AlNaRaGo2.\k$ns]cJL*Ck0#<UFBoBRTiSnKo.5Z@82Np$no>oZ[5PAY&cZ%t/4j6IF1XJq>FO45naH(f&n,0034NpRfc2(d`t8O-^J?BsmLOAb>>HYn9Al\52R:'8mc`lba#e">CFQq;Uc?)J']0BuhH6G[7Z+NT$h:'UiC)6PHtd,cE?n^P]Q(h.0BA2,d'L^51#=1PB-[BMR"2_kqTd<UYe;iB(BJS:YO\3`P@hfWoePrda.E"XAACKmo>>L)5#hseB__ts704;\LG5<0%=<?<(`u0F,Zc`^g!aKrE#\7pr1JC1R/`c\aW]9ri%1mXKUjL\d584tDE,fI\DoVp8+Jh%pC>,sloW(h*3NM@*fVgA)2^%;F5QlB-po!]n"h/?%TQc0-!f2R'LEjE*f^M%LOo+HmTCAI4al4!<F.rhqmJH[^BZ"p6S#6BWHR5)YTYYQ0$K'MpF<;L0P(mU*N&acE';C^&ZZ"SM\B(6I#$`EH79;;g7[TsdY;ULa#)<2kgd^8C!%<mk`?J<NKgh=&dT]j>&&(@,BI'%iXJ<4pu0HG1kO&nHUB#):LP82gBpUg#@c*D$Qdrd#]-uLLF]o980JjS)RqrB!rU>dX8VM1*#:$XV"b$QJSVYka>MA\]i"Qr`OLCOFI&kD0i`O#m;F#3_8"'Vh!L4<9`>,5Tp(6~>endstream
endobj
32 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1476
>>
stream
Gatm;9lo&I&A@C2m*X&_"+]:B3KEK@-Z8"4bpaHrJeZoaTn&Bobk/r"6%G[X)mnFI1_QeL"5^q9pCX2dn3ahF]E7kq_1sfRPX2_\)L)9nTA_VrrL?`CN!MgCKOBaa1hL0XK#[qbqD!6kQ\D)5ZPod^#71KuJ.f)61V<"Nd2rK6;a2QP'?DY67PN663!=MfQj7[YDa`I!Q`X*=6JVMDfaVJ1[&-JXiLh\p4f4Jb`gMg%`=[rj!5+E?1nror"cW,Ils:/2\jZ12.*OVb/K6DnK7j>t1I36Lhsb&(W(DBWQPGe,'[L]?(8,>k6]3+dGg0<a&p4SaPU.kK;lj`=J>H5L<'lh^c@p#i5q_J8;ms>VnIMf>cr@Y/TbY4TE:!$lb6Sd]A]sRKlhF68(sG=LMmDEqV19Y.UMrN0P"c#nC+RpQc-$/ieT=^@k0>oL)P^BaGf%XO;t<ss_/;]T&\p?-XE[t1R'p@@bo=m4X?6+M?QjMp?gt)lc:'<AVp<Ob1ef-/?D?#Y<1#LjpPX>JMnGuiPH*99Wk.+Wh;T6OXhpR[lDuQEXA-Zl''.IT/`'Q/4HV3.U#A-#h]TAts4tG'CL!u0$cf2B@$<S3`!lR*4AB$q1lWW6&pWk$lZ>4Te!G&ZGBN)$?>=MP#*d,i5)(=WH?^8I^djSse8_n&DPkZXYF&JQhFgKCBr(?@oZ6%dh&'4'JU]T[HXc&ZUdOfsFHS73Z^_JbjCYdO5O*r)$iE;/gG:Kg9DL0*oq>AJjq8mJIeRA5]'=Yre%Y"r@'Ra&9FdAgnQAS$\aH9)mArm9"q;]q68)!"UHQ]P`NSlcF.NeUEV!E$I)!32rRf:jN"S?6L!j]O!kYR&,O5+tM-R("riE\es2=BNbR;jPpfM64DM6slA6<pBomGnUE4;n(W[fNH<l.iQ,rS4^&[I0H=!*I@@Q-S8l!n-t&Ipe%?PC<j';NLiW/pn9QOcg-pS150_C*a3(^/Q_aFD^FPcJ/1eRHp#3<TeCB5E54*3q#GTXa5@9cZ@>+k#QS5+4'80:FF_VC#f(lfp:mL>m5JnQ0L/@g>"d+1'E`L[76cor7ZG*rQO"A__VcYpW/T.QI:C>CJ_Y\O1KTGu<f(MHo04,KHBt['J4qa"TiT[i`=8Qe9:88"n*S'%?cNH+hqim`mE(!l'.GSt`]mfV:(9Y^[LW*KJ=[1o5mM-!Ztai<h_>W$umO?q\/R,B'.0D!p<I^#$N6fe%%>l0KF\hWLW'@^b40E(*u$&ejlFd8pjO2n)C?B'hA1_9WLE7[n@<\%V\=m)6tUr=mSLFQ+<QjMZBi[B%q.)b-a=(T2m%a$"E)N"1/`%[+Z7HZ*Q1[qc*44<'=`[niB(io[>Wd_!'Wc*V7\i[)#n*B>$B2bPjX#mml%9N>K(5cAmpeBqH.!3rZHnI*loj7R_:%q!:R./0<(mm&=[G7u!`iZ@!t1*nm6ms[gd++/'>iTODFZ[W!6&u2`~>endstream
endobj
33 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1739
>>
stream
Gb!SlgMZ"A&:N^llB.#^Nk9_32jV6QFr?Gsc:X4\<fZDIB7+-H8]#.*I]M4?@k]gdAfjJ]'X4T5=.QKDG9<<)MB=%Vr<V=?(XC&(#R0r'Lp#t":13/VIe8FaROX]5M.!\>`1i"SJ3nC<BGN#oRi7APp0o-aYM0bi%4Qpb&%rq@L49bbOU@G2[)%_U14iLI)5glt^8A]"Q[/>^R_^->QU/XhCm2.\E1arE^kpl<Y<-cZUJO_Sd&rMdhFbDs$NI5u'f%%[4ub(3:b@H;i4_J6>r(nMX"a%V/4a7&XP"LSLm'[d_VceGi6"DAjFsfdQL^,j@Ib&LO,trGF<TUV:*Z/#[HVpbVLZ9P)$<+VX]?/[d79!Y?@lu"/B0]aM"8>Z(2!ZZ$0$n,VEqXj>15kf(:Tk^_j5J;-<%<gSM-?i-35F=g0p<>U3&L\R&$Hu"@bp1gVQX]@(ctLlS_LmAsT]m]L%WRLh6-a6Zqb.Z)D=eMh5PA)QR(>EA!MVe\MiFWSj9%LOTcN!->Zi)Nab4#c?cp@h0@8T,cLUO-?G#M7^;nP:-'Q2_L"hk_*%R>f@+lEj52e&:*fSaCARFoCHpnptTnE*%@e9)aoW$,n8K-I!2T@aq/-RM5D4%^'t;`UXhbpA$)T^s%R!3VYE=D#q@fJAAd/TkT.)^"ETU#%3Nb&X5'epYX[_.Q,@H5MKkj:i:l$[p7&^_At(S^J!2[7\<?-[bVNR>8^(kE.OGouj)sUI!u<L=Bs3%,8(lkVm>;p>&VnuD^^Y:9aAO\D04kBjWMBU1?u%t9<d\8R^f>q;ej9)9d^TeHjDdTj?!ali77%6K/=CCMH^;)m8><;#QX:!(48<<-f=E(2^Q!jf)[=-1hhDY-;[a<ZZ%)GE8^p(0JmA#<iJk"?o<U?tL!(t_VRMa\)dNc8]2@o`%E13@1'DV3GsU*"<5L[OQ0:F;PKSl84)1]t::3\:hn&RhlXf!-RK'sW[NXCkKl".jieHP$l6VZnV^Ij)n>Z=XfJO0KED*X+\?F"DaB6>3,?RRj<u**!r!I?ipds+GYm@/,M4<OpOS:Yj3&XHuGAt%BR^N@jPH)$!F6%!s\=I$R-84t>;taeWk$9Jt5_f9iR2;tTF820n48qJ;']$#o%<kV'6</n-#/u!)AtOF-!AEP;&W'5H?\RuD=:<lt7BKtgdJ?Oc\4A,VPu^dlaUX4V7rH8'_M6)uDSqCLL5/*5_i)B$M_MMoK)%5,-#p3M6u38&`Wu(8h$A-33Kd_a,<'`g5XeuE;Lk4arbaH`<Q0Jf?>X/eZBQsP08R&NWu<\KG3%6)_nNaO=D2n[;\+63C1<mm=\V'G3I@)p0TBsZ6/kXs"c;Op(*rhV@R8>L]tD28`I`bd'FTWTNab;k4,\fBTlMJOr7FHqN3?igbKnY?q?A#r+A3V0ql_AdMMJ)>$KlYX2<^Q/a0:5f@OY^hb6?'cj>:JU&1ZQ!oh0nG:"hn`$o]V!&c16?Z4^?2_eKEbo-N(ci>,<RjREh(F?=7f>U`n^5.:6#I<3H[kL2$jVdShfRt`cd.if&ubg&BNqWXD*Ch!ESTjsG+`29Gd:5RX;3gH-2glti,s7PGKag<CEb)r.jOX!BWO/_MQ7ERtE5:fgRQH)Zd#nGfqfrCe$WkmS;M;-m6ACtr0H8:L>"6S/iE\MDd2td+;r.P]0"IJr-3:KeUbI9Za6O2nBW=Wg0NWpYR%G#d],b*u-Ae=_VW(O)nDL0\,#;U!Kec~>endstream
endobj
34 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 955
>>
stream
Gat%b?#Q2d'Sc)J/'_^0Xir]Ui*B%!g8+&'VJAXY<JiW\`9Cq;U]f7Kg5k+l)a_,&<hTZ^pu+B>5<+B!_2FWZo*F9<&+<"&-j+r*e?L"_a"[.4O$.5K5sRtl0ZGXnM!I'/EC-Lp@(D4X'%4B5lHi]Q73[t--s4W<KkT?r`.Qg0q>f49lA)R;p#Z8PHghQ(N)t7@ZapQ)X0_(J(3=;,]3lBRN#-3g!_.s*nDK+JO=F?RU.B9(h)7(Fb]I&eb=RIe<tojRUf[/P]\n"p4RZ!Z6?J&EcC;c)bE::`jYATQj`E;bL5e&&\.j+k.fE5C<f=u)2]sQO/a#@%ea"';[`*"L3/KRs)ME+=Goa@#D;ZdV1Jbo2(++#'-RDuVK7_]0%P"m$@f)[dFH+5#K02dRH$$+8cLDbJlh'OQ0YN&/iD&K[%"94PO1Bj]U#IV.L2ApR86=!4ah>hXI2d3s`-5LA%5tef%aRltqtq@YWg8_mjnksHZn.XGQg=;OZBf?(H>QK-(j0^5K2+%IQs>]m?"OO,N3i-o(8q\KI[n2/cgk&[%b`ITZc*L@nm#TpNjYh/YlQAqn),FP0&)-\SE/o=*A>o)N.P'A?^l5O&hdN0pd.D@QY1s<Rpgqt:XTJMm)q%IeuO1gWaLldq;5DnOMfK(HAlp84O*_>ZXn<b/igoRA>m8bJnWtbVDpoVi:"Bm3RT-1(/q<5K].nH/?:Hfm9(F#lD#RRCMM7#_7)1'`HEK%_<Ba*T.J8+'?*umV):oT/06&tLlEm=VhL.>UPe"JTju`R@]W2>W[p-%U9mlX[[sG\ik-!H]!^p6P+*NKWd:hl8Sh#(5#R3uR:=r,X1Ou(bTiG6&Iu7r<A1j\i'N#fr:TaE%_hTS/p<5H#4i)8&d:e`X81($S-LR[lD7AncW`;misL]"[h]m`eF.>YI[]?4Ai?RV#8glskF2R"IfW^R&mY~>endstream
endobj
35 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1560
>>
stream
Gatm;>Ar7S'Roe[3%l<#0%EMX7d\H?P-m[21l8N9!.ub"N]LH.?'9@JqV-3bOcg_RapJu:/`uigiQ$!U"bM5'IE+@`8I3)$;kOQ9"K5fj&73.T\G1D:2:<`-E=]l6Z`)2T-NK&b2RRt;j>V.Rg+3T('(9cDN'em6H*b"YC?-H<n0FbAOW;4X:I[%#-fYt)pW0VtO-:l;.+`;_?s1JCBd;W7Xi+u\^HhQ`;S1A'#C:8q0hLl6gnpWiQM:qCr:h9cj@D@j87#?4\Ds9>*oTY0M^l\%g*$`_BlaeK`$MR-Fb(I"ZAGlofK_]-^]fV<"L_<uLq6@),0Gpc6_941&SkXRKk2l/e7ksWi*!J?7TIsr#.ZlLMc`qI%7ut!jeGfT=k!n\NT):E7;^9fM_]DFfN9cXEbR(cptPnn,rG*>=IniNg<)-&PX[u<)&H32^WQjZ4f%(WOq&eVidd%+:7d:qK!Bp*;M+,A2UaD3a-Qp*NuJ(?1]X)E<!Ei/^*fO*$$a5&ECN%`<AO,t.KaTqUX+BcTejF4SjG>V"dRsR!p(T&PC(?0*;r@',J1bJc*Q5ZV-]5[e5k>0ScIK_[X:Es*dr%=RR"I.i^(onceBY0&ROqAM8G]cd+MX5[ShaGpZJP-P&rL$'9-:8[ka?_gZn/%8cE'U;:3llpZ!%O7'D3+$(Mf66'&Teb^U[h`*(G#rtmnp)oZ?B]Z-S1<=VI4!NFtjLBQqZ'QMaq!iOq9@6FY`.JdW62,,((Cl"]Q9sfkaoLtWH&_Hg.p$F2m>LAkO7cL<nO@A%po`B3J+,dq!brs8E#%H*\H&B4o3>F)B(:Vs*DiHnoCK\DfaN@3qb=GJLUSfjD%!/P%\hBFUj7j=(fC)k7IGL2h1JM%?YD%YG7MMSXE&"]L0\4uc$keP@V\n/U;Vj=rS<Yu&S]EK?+>Lh8q*&0k?-adMiN+o`amdZI2/^jb6TW@(4)*/[4VaEKGR%Ta9pnMWM'k&3j%B4[`]=d($1f%O*R*7=aU\//I_I?a-fDq_c@PA80RUA=HO*mV[]j"]m$hUi)h_I/E22KHFC.L\;!.N8p<-cXjDs)"Z(q#5>k`7sk`KX*a(fA-\27*"P"(=%,B\_cS`)sp*6??LP]4TG4pTYtG>e5VUpeP@/\@;Dj_?n@fe.bdG-VuMaQ19IKd.^F[2AJZ2u"Ma.ZJY9B$?%oa_<E@5_XGA]+216oPfL)MY`^_E`uIqm=d*6^OeLLnPfjUE/L22K1#4ga=M=UN&JPsOuMVi@SGuI7K$u(T&o&SgdqCN1?RZa[@K#ikC@)Dh7EbobA&i1_VA5!<7h5NS5iQl_7QXJb86a)(Tbf`[*7_rK"Id+b@'(RcEO/=7K;fK/F,ZX4Q`,\J%EIYD]MjD1%!/dC7EjoO^d$,]tlGa+t?DXdUkIuje=q>,@jt:dP#=>`lHP/cs:@(VNpU9h,HI5dJ$9>j&kY-c8i>bc/^WY\9p<4'@"J73pLnH0[3%BmtuV2VlGEZ&;p7s89(/NCQXEFi7mAb3ZR%`.._dSb=m:XCC$uHICQUh$NHiAfRA[-`IBq%eS>~>endstream
endobj
36 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1416
>>
stream
GauHKgMYb*&:O:SbgRaf>$7XLM$!AsS&F,gZp66YT)pP\R80"3i_i[C!rMLL'Ih.ECc,q4JItNm%HkqTNeYRW>l9]W437O&Lge"?5UaQ$+O"7*ItX#1p2*:#BAc+l"*@#%6UL(E#TUuLie?=SDsDtdSeXMt5N<G+#:3gOG';Gkd3!HqUb3p=Eend)7V>dIitB9nn/YUf78g$p+YpQ0b9UAiM9u9(D]lcJpoR<ZbXNWdoHT.V'Y!JZg3)\3)fc.Cmuf(Ai0[-VM.-Bh?A,_FFEnHX.^>q+'Qp23ra\>&N-RVm/[T^=!"1d!pS]C>-`_[>R!DAnII'@VrJ2'!(9bFkn_P@e*;bf67DY1^ksG(KA,Jp7k]S8A?.#t6G(K(u[ehtkKEL`H]dX2Pq[MgL>KWkWj0>ZuQ*,8]lur)S+mMLU;)e6uD4S8f#Xf>odAW%EPbk[aiKG\.[ES/a,"K7Ud:=+7SUWhX<N.*T"'"bQX`#=2McqD!Akigg7:s@B3;%Y0hn(RMi?j,&ZYXD7T_!lPl$)'n#[=>?YgN&b->WF8S@F#Pi2J2EAb&Ai`bR'Fdc.<46=#V>;50@08W/.J'j<S2.u_q^_F[V*+8a`qY%LItHj-Kt:%`]S9:'+gX.Mt7_0Qh#r3.d=Yc5ecX%;/>A4_tJ)"(UEfOa7::)8hBWunQ(>r"@@nT%kOUfZNlo5%:i;Ut8&(/f!flkU%R`Q>f"+g*R,VoO_kaaG?h*3%ZeJhMiZHPImO1cuP]J1nP2H]&*gIZfUGHO&l+ZB4MTf?"!Rj`oq7e=tl>r4AL[/E3gfV^!7F0#``?lhnZEn_nhu"nMAKe9@j>>,uFUm`=C*pm@ri=).85Xa&H%C%"]MQr+)/%I<QZ2`A>5Cj>._)r>Zpg;2,G7H8(rI2t*6!gC71G1O!T6B4q2n/Xj@Mlcm16B8qG8h0V:W23[S6r#0k8qI(d6M]o0kd6T?U`"ZPPTt:nIh[pL-UmWZWF1tZHho.-7ZEoe<B__QN7Vd=en$]r.42<uM6^%T5DMhYa>BC7=iU9$8.1q!e]h)CeC#>4Kt'dZgK=Ql6&#.gXmeI,EsCT-_0T3.oHm<`lY?Z4L4Kf0=>&cWRF^u+gmSj#W$(;t=tMQ7AUQY2Q1m>_W^r>j.a>3FpYgD1a1DmsQ-*4klNp8NDkot,[>`K\QNt9P/lXTW>,Z4>?bY3KW&N?Qre^!+.fIpl8U>TB9fK2h'gnk$$9(ei8)g_u?.r(MqM;[TGKsL*0m@sp)cl;!filMUbIcHLLC*?lZe-@31%"*UjZ@*+*DP#1RHloh^.Na^(lqD6?&*Ea`L^p!Cak<B@O-Ht-M\':qb'P";QL"E#50=TLKGl^"o`hoi*<F\P!uZhUKJEnKSFoJ_bApb'u[+gmOgYp^qW-?lAm8Lbl.^UiU>J~>endstream
endobj
37 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1592
>>
stream
Gau0Chf%O5%"?N0_3YVAgZhE%n&MfG)`G'*Hh$f/TMQXTG3`6j>>AD\YePUN/NZN;],e,K8E*O>ac@W7OVA*#dJ>q2!F/$3rfmOr&1rDnQ35MLI#1>M8(8YE!aae.(hFKURHoN60up0"&!m3,/elK+%TMJZJ,p%N&?tpl\ujNH56RXU<[AplLfS1,_*hMI=4$BfZf(]N#6)?(^e>F];8Au*ElD$.o1oo\6M+EE]/?%d"PqF6Rc7O3oc*]Loc7WICt^R1QF,<Yc-12pAG?Sn-qR'6(\1GA$Hbb#a1N*4nG.h%Z'YX^pd.uXq%?XNC4ETt`i$H=[@E-`/nM3(Mh7Eb.N-FrmaJAAP=-@r4HJ.'?/$)SJ&o"2amWlT/CRLjZ+8MC9WhG@=!/;5M.9C,Qh<C4j-i>L5ts>APerd5`-a$+H6IR(i9MnHW.HNsmMR']dYg^t(e3":kDDKsS%G,5D-KB$EPhd?l7b&tBB2*1*q9=;/=4`1UL5sAH5da"9c4ra$r!-G'W*thn7Ajqj&G+0CG.31JSdJQlN9.AJ2%9K07^A]X1O>Ab=MEQZ5#:_6AJIre%[NOjD".?*E)'^s/$8:mXVn,/b`[jmX[%@AI-7K%%-G9\2V.bpml`^lUtMaQp0^p;Toi?ST"dXn3%f=nP+V7[1fUs3aqoOf)`XN.`J//k/Y;!:b?c%X,:Q1EAf,o(3qK2,'Po-)V2Jb+merRqI-L9g7FA).+;`kj@f@W:&:Do0uS*Z:lPi7:0/30-N!K@\[loh)b6W%TEu.71glfSdN3UIU'=*C?C5/9J0/:Dll'+F9f]D_D/hVZe\LRG*As4u>rO;Dl9d*i\&Q^2YMci%764,jT\nEuK4=eXL8_q:Lo9FffWVS_%5Kb"2R&)D1;&GJ1lI96Xl(#*k'?De%)<@bUssVCcS1XS+AMIE&C#DA%8?pc@!>G_B`IT]h#E<[=+dc]@Gq4H#4^%/Bl?7sq\)B^9#-C(p4BGc[m0BR37=o962rJeoRu1!;o6<J2R6S4md@G^?+T]-#.%K*N/[*pa:>(M4a^18JrN_oF]/.p8Fb/#SQ:AllD1r/7Z(!D1h^S->?bu\b2$61XWc9LTe+-af9Vl'/R([`\c1DWD8L7Q[Cgd"=)JNf)Olj6m0jBEs3f,q\l"E^bY%Z2g^EWQ'BY^kHoG2iTN9mUXkPbB^WV2u*VFiZ%;f$m>ZCM^Y8bX]mo\LSc$HF/$th8b?CalqY<WminKP3ZI&B\Oc3XfT\aIT.2\5fle`J',)#J2aJF??H-`"?4=c,q]ct)T&V^%.=$?=WOL%7*&quu(J`(u#maU)Z7KfUl@\pp$b;jdo=R^\9p550sbH`EtJOD@]MPK4;N)Oun3L9jdIak3N!mDM3K)=HjK"&<Ln_FuqAKMQma@_#[?RHVcRbBgRa_*h/A![f_qIQl4Z*k_e"5?7"j_DAn;l4k42#nLJgEEJ#1ShJ&k<pXtb`!X`-gN0@]=&nD[<p0c@fOhGI3:5]2Jg2ghO5I(B"2<N_osG\QaAU@Ea?(#SP%-+Tn4bH%JJ2V@PiDHtK/12?1s*ZDcJ28?X3I2pXmZc_QH\0+'h83)`n;IB~>endstream
endobj
38 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1024
>>
stream
Gau1-95i<6&BF8:.HZ:!,gt=b*m:ZJMNC*_&T5:l?>jRtm)A\,XMfm,lt!S0<2)tf77ncEnbbL*s7$ZAnKR3MH@V>6S6Z[K'\X!-Q8*(1_jbi>@mS,&<=W#-iFEqO852acJrI!e'K'Fk:.oQ^_>oGa=[R`ui$<-1/O&,HB]-*-:2$<fj**>#G(DI@A2[_rK4UUi="iMIpX6qm38\V]&j.RXr)7:D62N4=I7am>ns-877`%C1kr9a+X1W<eA7\M:'nL2R#_JZK,(AU2A:u877#G(L/tA/p)hE*%ZdXJp0ZfQG#M\u('[Ztj#7h@YmJPeDYl#]@iD/&Ba]]$PqI^-'bZ\m1hFmohKS#d7hC6o>#sp0?ki#QrC\5:tSW+`"c@1s$phX[IAQ.AEn#p.afip1KmLF6hk44\b28$C="P$.IF/AVM\YRS&F116.bGUO@eZ9U[jc,G4E%C$oUq!ipkM^0*nAlj\Rhb"d1t(n:Tsl@R,KgWK<6j(+0U_>TSX&9\cY*oB`A\qtCod^kK\`&HaYF/hncr.7RX>mq;>AR\Xl6\[W\\VN8L*q-3394\YMb<$>NrdX&1$]f3%hp83Mj+F_HH>;N>huq.$:cdbnnGZ;Y@?16:fH.]clrVd[Q@:8Nt'*KQ^X!Ricc2Li*Qo=Nq+k<7lV1!QPhP[.M0Q3N9?ZSrr.Mf4(X&c5;N8go/#lPZD5H.oi/u%g]9c`pnPE=on*GGco#M%b=@kjOM*1Ill99j;[>H*rK7RVjETu.h(Y39]K`Unk/?m-T0V^4)b(E4C>/67_4gc(fYu7Za0[P&uM*4VN%DXr,.uRq2IW$=;'I9#b)RiK/EuLkUp%?]6,L!O#'Dk%88U\jVjAoYtE*BqcQQFSD$0^99*<I.]jFS2)N,e>;^\W367=_I$A`la<*7GY-V-aPUOud[JYiG04J'hW][P.nk7)t/r/+3QKTK<+.\,K=Mr+c_4F_<VipUDaG8ATFd3PB*u?uinu)&G$$LN6=d0&<@<YGhHWu3CD\">\mf~>endstream
endobj
39 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1255
>>
stream
Gatm:D/\/e&H;*)EM!H56"lAnoht.7oAX4HMoLb-IPEOt1@6KP7$XL9"k\mnOcg\ENO/is%%G-(\\!WpkBNl^i.p%DZiE(H@CDgo)8oaP*q:BP#ZpQWqh2CKhZ5t6&WAV7"3/"[#kM<d#!gBcj.LRZ&u`Wn+TiL3'!QdC=eZ9NkTV/mKX``5Qt3WjUgqm-O4qE,,k,#@lQjdiS]MLnJP/l%o!&b&5(WJ=icg.4dRNX<j:PgTic@1sm=r4@"JH'R4#HLWOQIh0]Z1TZ)hNe_odhsn'mWZd<^MZ3qlJ)MW(4rhr$gl<]m<ge#M^XXeq#_4_PUVd+FnB5\WIC[<c:Il=C*&_C#2WgWam]j)Wk``l5F"FohRk'pq5EpW;tQ5n;unhG(5aFs0gDiU^"4tpF=XQn):9?f"$=7kAr&qei4I!7$[eR'i&!1s4.O0jZZ?+iC520<46,K%On0M.Zm58i1#un;:m]@Z],\RXE^qRr`^PnQN[go%jFZ1=dkSj74q4f6ZJC%9K#]rGpcK!N54UKPd"<:iiE]r9%*TP,tX8sRl.^O.sFp,Gdp0nqA,>3S*mX^%m.>#UscK4Wi0>`h.E\<TJ>Hkj?9$L4P-J=I(.[<[d]@1XVgfeNFU[Je5ptHWQH\rcO.59kJFBO/s+`]50GlOO`b]kbk);r[)u0/]JbP)2:(lJ4n'tmY=^A\E70OHp2sF(+K;A'9C5_=.O4AoTP'<GDk^jQG6als%%6)R6BSS;?b<6n=R(P%LN)C]<n,qBYhSASG7V#jX?k&6o*g'^%'9WDG5O'NR1AZecd]!g#a'$41MonD4*Z7ZiE9@:V.cY_Lir7#/bWFW6_IV/5f]T[@W[j%haG"@V<$Y&O'8JjFtNDS<fbTcZBhFEe/YpeD,uO&[]T#+:phj<gj$L@%`&Sn8gmmQQ\eJAY6Mds<=<.^M<Z`QE!gBnCWmI;r_hqbWU>Oe[GJ/Z$G9\o2751EW`LQ8oLq+O^#_bo&aID=_-6'#Co7mt9X12%3gR\5>&W0FQ-,,%@%-2$r8(/((PRm-RRU^I$l=r;6fH4D$,O`0k`Wf?f0&/6A$&LAF,heH&(BnEm"oT0)"F<+nLaup_I9?!2LK1Se7g+qodQWY4DQfiB3hri67_$WRWD$PC3\[dcc/usO=1CF)0o81a\J3]O;Nki>^,U%^`2oSCuM!EM5)C5l"u7nBb"Lg(B;@=l$t1q^aBiZAJ]$OMncP9@O:b5<\C<>2\&g,O01^7qub(OY^c~>endstream
endobj
40 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1317
>>
stream
GatU2968iG&AII3m*WpG1][Z*jA\.=46bCgfO<JTHD)cYVF(t'#ha3q5JE$\BhG\5BJLKgR)O+?_m^.-JIm=L50F/g/;M\q!e`nS"Mt3Eq$$\b:VKPZf8N(Qdhn?I(6F2iQ9dc=7%seco;!AUC=3/<qCJI.;c!O]D^SW;N;9.KHKn5!AdWg9Sl%L)T(*KdH]eR%8]dgm\k9D"%A/?cY=d3Yr4],pihdK0+MWR,Xat`Ym6AGJ=[3GC>rgq?rosMRpd0cV4G6<H0c")E>BR/NnkPDf(8?q.VcBE&TD6,98lqR6WWdg/VjDNX+0'JfKb?iKmT&%!7c&?.-PTZ95<sUP,U2i"$F>P7l3H%f2SguW4[^X<S@ORjP/QM-_^li#=h(6AD%<o6(iq-Qbo2Y(1.HJK1/9Ne:d/@<-h;H7OX)`F4n4@dMTT$SiB]T)ILoeaWjTj**3"]oGN:W/bps=,WQV;@ZBIojo+JC@K+HsJe8jB$<c:@1WV<\i#LH[<Q`B;IaMqC5NJg$Ik"om$C^Pf?$D4LS5U-3)qR>*;`=INteF?B!ihjL"7ma6+Ss:D5lOEfDG`1:.R:<u``-3aHF+U5b84A5t?aX(=<2C\7J<dN!T<u6#3X@lYf&>;ZX'.mbI(c\`de`?ka7$-9Mf5(W#no*?qodmL#RheR^cnFY3>Q(0bK&dtH2qk'>7]?fD0F-Y+<D'ERkhP$'IN.CE;BKsVq!U'+P#'iG,_+UNlX-LP7+WFb"&t+$_c8j/0+r^NVVS\d\a/r<M</0`!nPga*qh3]0_p8SB^S9l*ORjAEEW-7RA-,D-kDF2Mj+$Mj5,ZilI0po=s>cDA'0)%3t4_f^_@d02Ae@_=_`1JA]:Og`,#?bR-!l/+$p&P&R5WG5&a.[t0a3eKAG:Y#u33,f*,neP!0@4!?5&)7FN4_aQ5R]d)8.+gL"PG]Ki+f@Bl&a?gZ<]=6dY`"XDY\t+KJ,0hcC'Z1@:m]tJ_gO#'3EeIpojG0>i-5c@H",rWWq?__W"N,su$TNDb>@$0Wn?KCWCRbF3Ol"q[^euGI44d[X))j0>)?r0^q6-@Dd@fL(@^=V<<BJ9egt_oCEFO?#k><31(42:"<RXE1"?>-5Z>+@,$;/t[+5fu7G^l_nV/J:OB)gA+YR\U8Fclk6:*E[8oK;]SY\SDtm(*8&dti5;(Ri03M))T+)q@(`KA])AG,XZ3_Zqd"-Ok^X8*u!Kg5["EOs!CqDSg.XCk9Ps,*6Jq5<fAqNeBL]*)Yn!.)25H'P<Gbo!ZN<UkWZ/BtZ>rYQWXVa^Ad@/FXaY)Wb2`+\_k?OLEfI~>endstream
endobj
41 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1442
>>
stream
Gau0C?#Q3)&:O;VR&A*/D@*p+?h_gMSMZUq3Y(CQV22u8+kM7^LO19%++Io>f#E^n`DpFpT\8!S#A0>`90gN>OoL%Ni7*CC1BN5]G7T@@%(mHO]ts;je=Ms9Q=HUEg,*8;PI[>`Ae;ia:&Ln9A.O:qM"#$e"mS@miVq<a)Rj)SKnKpGGd1Ak+=CgcWQVO:QT`-GkSfC\/"VDk^iT8N$_F8-LA)e+HNNZ"TQVo,S+KBUUOqF<S^qsMgsU%pJS+2c[0UHrF!0oU5@cG2$"AQZ@ZmZt7:;8_A^$@T0;::SZY8%.aelkpDo>DtS*CjAEo=8ilaN`tLKl19,aTs\QSl6EJ]e>(/TEXjf@fpT[cbC58+g2-Y184QT!JY=gOGG.0\T-(egM9p,B?-:$>h'6_+a);F[M:X7Tu8"kA7ioA[Y5&VP>cW<%J5k7juiJ+H,JtE]M\0E&XB`RTao.'(u6LQ9Oi3J99&BFi8c\T7l]=7_q<N(OfEO_fh6<Xp"Epj"FIMj3d420g2!YVH;ef(tN*T1gVbZ_4ff'@hJtE&i4UT1S+`^+$8;CJ<Q*S3Z[#r6V/Hj_T*@G&Gh+\e'C&8_'>$>??@/2Z+cijmOl7KDJ.Ffre.]s&>UJ)Yh:(DYqbXG*+ktHr\W-e\s>[sk0%imLqmcipEO-HFZKFV\iQJ/^7G"2;^6\Q=Y?0(A!@dDp<nje<I+?to97Afr(c>:r:XT?7*/D!#Qc2AAaVd%GUT>k=h:>=J&T1#J]:qb2m@F5s3`?&9SuOQ(?YeEKO:3D*QoKMmZqf:Xie(fd2P:"lKb"8[9$CK\$9BEYH<&YYu68umZ\HuF(N9/A](*Eg$hJaQjUd?EMs43<><h$720`A4Ki*f>Ga4$3A>:Z]='pGR&OUPnuKmd3YUV^V(fg_TA\?"!H(?c\u*5Nl3H;e\0(m[.PTEVW<0OX(`<5p[LG!V,V&bJ23Ydj]>>H&jb9UGG1&2'PofY_QtJ^<^%q@5b;mo.W$loCacX4da3-;umW!W1ep&H-lFndd$$N="qH<e(6i1.,cEh3Oj![)TaV;K'G2U!/['p"F8iArBreoi$c/S\1pdujeNR/[n$df]SDKQH3>!htL]9T>4]$O-O(Dq;K^tod.7!*T%#Lu8Zitg`kZAhq^J!qaG?0+\iK=S'MWPs`e=*r_K"4?`V+$=+;dKP\KbPE0-)n+VP"`)2Sic+&C"l-7Wmd[M%YBKp1-`*HK!&=Ji#tE0?E)N5/DG[L$H,j.@Q+@=G5X*kQqr,`'!^[U+)XVGNLojHO5W!\BWirO847!tFfU]-l0U5Hg[mGWq;*^Bp&;!7V!5,<k8c\3+0%&p`nnNI8h2Xd<>B=Z%"J\Td>Y$U9*@X=_j9T,,D-#M"'QYr!nQ:HiJC!.j%O6nLLCo6VCeH#&h>iP$r8/n-02'L]&&T[^hgU\m%q+lkX2EuO~>endstream
endobj
42 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 479
>>
stream
GatUn95i?7&;BlS'k^Y\2=W2X,tKU#@aSDmA7IVpDr;rp[W>lnO(WK?"Bm&rAAqThj"ol)LSLZ]&$m4+[g'$S3OjV(_%fm&+)k_IY6@.%<[FcWU#][hMXj62Wl,NVK&>d=?SL"gV/3uTC.gjN(9QT+Iof=!@j?Z,B\hVlM/E5?,3;\h0.QLc+LD"*T:Cr&?%SD5mu)7dQkl-69nt7**>5sAk0ZsBaiD(jYR,U@@HY94EQC$KH]ROLFrHn,_+l$IH#e09'E(DXqrfEjd>%u`N8?tg^>LUJp&aA4bY)3EMpg-=-0+q'aVrE7I3uQP1S*G#?$JK9fp%5UmGa=QgmiC%0nsT0$#2atYMd9^Xii6k?Nb07$c/f"g4P0D25eap-O<T$XK<EN=Y2=/GP8k*CBTgKkHZAA3hd@(IE_]XSoG3\H(Op)HT\L*lABRY?\I;&r-.E,'>qK_,W3UQLf1;`C^Lk@!STQP]D~>endstream
endobj
xref
0 43
0000000000 65535 f
0000000061 00000 n
0000000142 00000 n
0000000249 00000 n
0000000361 00000 n
0000000476 00000 n
0000000672 00000 n
0000000777 00000 n
0000000860 00000 n
0000000937 00000 n
0000001129 00000 n
0000001325 00000 n
0000001539 00000 n
0000001735 00000 n
0000001931 00000 n
0000002127 00000 n
0000002323 00000 n
0000002519 00000 n
0000002715 00000 n
0000002911 00000 n
0000003107 00000 n
0000003303 00000 n
0000003499 00000 n
0000003713 00000 n
0000003909 00000 n
0000004105 00000 n
0000004175 00000 n
0000004479 00000 n
0000004642 00000 n
0000005794 00000 n
0000006369 00000 n
0000007117 00000 n
0000009075 00000 n
0000010643 00000 n
0000012474 00000 n
0000013520 00000 n
0000015172 00000 n
0000016680 00000 n
0000018364 00000 n
0000019480 00000 n
0000020827 00000 n
0000022236 00000 n
0000023770 00000 n
trailer
<<
/ID
[<28de111491776d1c6e6abd209d41cc39><28de111491776d1c6e6abd209d41cc39>]
% ReportLab generated PDF document -- digest (opensource)
/Info 26 0 R
/Root 25 0 R
/Size 43
>>
startxref
24340
%%EOF

Binary file not shown.

30
check_form_modules.vbs Normal file
View File

@ -0,0 +1,30 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
WScript.Echo "=== Form Modules Status ==="
WScript.Echo ""
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
Dim comp
For Each comp In vbProj.VBComponents
If Left(comp.Name, 5) = "Form_" Then
WScript.Echo comp.Name & " - Type: " & comp.Type
End If
Next
WScript.Echo ""
WScript.Echo "Type 1 = Standard Module (BAD for forms)"
WScript.Echo "Type 100 = Document/Form Module (GOOD)"
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing
WScript.Echo ""
WScript.Echo "Done!"

41
check_hasmodule.vbs Normal file
View File

@ -0,0 +1,41 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
Dim formNames
formNames = Array("frm_Accueil", "frm_Clients", "frm_Projets", "frm_SaisieTemps", "frm_Historique")
WScript.Echo "=== Checking HasModule property ==="
Dim i
For i = LBound(formNames) To UBound(formNames)
accessApp.DoCmd.OpenForm formNames(i), 2 ' acDesign
WScript.Sleep 300
Dim hasModule
hasModule = accessApp.Forms(formNames(i)).HasModule
WScript.Echo formNames(i) & " - HasModule: " & hasModule
accessApp.DoCmd.Close 2, formNames(i), 0 ' Don't save
Next
WScript.Echo ""
WScript.Echo "=== VBA Components ==="
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
Dim comp
For Each comp In vbProj.VBComponents
If Left(comp.Name, 5) = "Form_" Then
WScript.Echo comp.Name & " - Type: " & comp.Type
End If
Next
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing

29
check_modules.vbs Normal file
View File

@ -0,0 +1,29 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
WScript.Echo "=== VBA Components ==="
Dim comp
For Each comp In vbProj.VBComponents
WScript.Echo comp.Name & " - Type: " & comp.Type & " (" & GetTypeName(comp.Type) & ")"
Next
Function GetTypeName(typeNum)
Select Case typeNum
Case 1: GetTypeName = "Standard Module"
Case 2: GetTypeName = "Class Module"
Case 3: GetTypeName = "MSForm"
Case 11: GetTypeName = "ActiveX Designer"
Case 100: GetTypeName = "Document (Form/Report)"
Case Else: GetTypeName = "Unknown"
End Select
End Function
accessApp.Quit
Set accessApp = Nothing

45
cleanup_old_modules.vbs Normal file
View File

@ -0,0 +1,45 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
WScript.Echo "=== Cleaning up OLD_* modules ==="
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
Dim modulesToDelete
modulesToDelete = Array("OLD_Form_frm_Accueil", "OLD_Form_frm_Clients", "OLD_Form_frm_Projets", "OLD_Form_frm_Historique")
Dim i
For i = LBound(modulesToDelete) To UBound(modulesToDelete)
Dim comp
Set comp = Nothing
' Find module
Dim c
For Each c In vbProj.VBComponents
If c.Name = modulesToDelete(i) Then
Set comp = c
Exit For
End If
Next
' Delete if found
If Not comp Is Nothing Then
WScript.Echo "Deleting: " & comp.Name
vbProj.VBComponents.Remove comp
WScript.Echo " -> Deleted!"
Else
WScript.Echo "Not found: " & modulesToDelete(i)
End If
Next
WScript.Echo ""
WScript.Echo "=== Cleanup complete! ==="
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing

36
compact_database.vbs Normal file
View File

@ -0,0 +1,36 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
Dim dbPath
dbPath = "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
Dim tempPath
tempPath = "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro_temp.accdb"
WScript.Echo "Compacting and repairing database..."
' Compact and repair
accessApp.CompactRepair dbPath, tempPath
If Err.Number = 0 Then
WScript.Echo "Success! Replacing original file..."
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")
' Delete original
If fso.FileExists(dbPath) Then
fso.DeleteFile dbPath
End If
' Rename temp to original
fso.MoveFile tempPath, dbPath
WScript.Echo "Database compacted and repaired!"
Else
WScript.Echo "Error: " & Err.Description
End If
accessApp.Quit
Set accessApp = Nothing

42
convert_to_pdf.ps1 Normal file
View File

@ -0,0 +1,42 @@
# PowerShell script to convert Markdown to PDF using Microsoft Word
param(
[string]$MarkdownFile = "C:\Users\alexi\Documents\projects\timetrack-pro\TECHNICAL_REFERENCE.md",
[string]$OutputPdf = "C:\Users\alexi\Documents\projects\timetrack-pro\TECHNICAL_REFERENCE.pdf"
)
Write-Host "Converting Markdown to PDF using Microsoft Word..."
try {
$Word = New-Object -ComObject Word.Application
$Word.Visible = $false
Write-Host "Opening Markdown file..."
$Doc = $Word.Documents.Open($MarkdownFile)
Write-Host "Converting to PDF..."
$Doc.SaveAs([ref]$OutputPdf, [ref]17)
$Doc.Close()
$Word.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Doc) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Word) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
Write-Host "PDF created successfully!"
} catch {
Write-Host "Error occurred:"
Write-Host $_.Exception.Message
if ($Word) {
$Word.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Word) | Out-Null
}
exit 1
}

View File

@ -0,0 +1,56 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
accessApp.Visible = False
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
' Liste des formulaires
Dim formNames
formNames = Array("frm_Accueil", "frm_Clients", "frm_Projets", "frm_SaisieTemps", "frm_Historique")
Dim i
For i = LBound(formNames) To UBound(formNames)
WScript.Echo "Processing " & formNames(i) & "..."
' Ouvrir en mode Design
accessApp.DoCmd.OpenForm formNames(i), 2 ' acDesign
WScript.Sleep 500
' Activer HasModule
accessApp.Forms(formNames(i)).HasModule = True
WScript.Sleep 500
' Fermer et sauvegarder
accessApp.DoCmd.Close 2, formNames(i), 1 ' acSaveYes
If Err.Number = 0 Then
WScript.Echo " -> Module created for " & formNames(i)
Else
WScript.Echo " -> ERROR: " & Err.Description
Err.Clear
End If
WScript.Sleep 500
Next
WScript.Echo ""
WScript.Echo "=== Verification ==="
' Verifier les modules
Dim comp
For Each comp In vbProj.VBComponents
WScript.Echo comp.Name & " - Type: " & comp.Type
Next
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing
WScript.Echo ""
WScript.Echo "Done!"

722
create_professional_pdf.ps1 Normal file
View File

@ -0,0 +1,722 @@
# Professional PDF Generator for TimeTrack Pro
# Creates a beautifully formatted PDF document from scratch
$OutputPath = "C:\Users\alexi\Documents\projects\timetrack-pro\TimeTrack_Pro_Technical_Reference.pdf"
Write-Host "Creating professional PDF document..." -ForegroundColor Cyan
try {
# Create Word application
$Word = New-Object -ComObject Word.Application
$Word.Visible = $false
# Create new document
$Doc = $Word.Documents.Add()
$Selection = $Word.Selection
# Define color scheme (Professional Blue)
$PrimaryColor = 255 * 65536 + 255 * 256 + 255 # Will be set per element
$AccentColor = 41 + 128 * 256 + 185 * 65536 # #2980B9 - Professional Blue
$DarkColor = 44 + 62 * 256 + 80 * 65536 # #2C3E50 - Dark Blue-Grey
# ============================================================================
# COVER PAGE
# ============================================================================
$Selection.Font.Name = "Segoe UI"
$Selection.Font.Size = 48
$Selection.Font.Bold = $true
$Selection.Font.Color = $DarkColor
$Selection.ParagraphFormat.Alignment = 1 # Center
$Selection.ParagraphFormat.SpaceBefore = 150
$Selection.TypeText("TimeTrack Pro")
$Selection.TypeParagraph()
$Selection.Font.Size = 24
$Selection.Font.Bold = $false
$Selection.Font.Color = $AccentColor
$Selection.ParagraphFormat.SpaceBefore = 0
$Selection.TypeText("Technical & Functional Reference")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
# Horizontal line
$Selection.ParagraphFormat.Alignment = 1
$Selection.Font.Size = 11
$Selection.Font.Color = $AccentColor
$Selection.TypeText("_" * 60)
$Selection.TypeParagraph()
$Selection.TypeParagraph()
# Subtitle
$Selection.Font.Size = 14
$Selection.Font.Color = $DarkColor
$Selection.Font.Italic = $true
$Selection.ParagraphFormat.SpaceBefore = 30
$Selection.TypeText("Professional Time Tracking Application")
$Selection.TypeParagraph()
$Selection.TypeText("Built with Microsoft Access & VBA")
$Selection.TypeParagraph()
$Selection.TypeText("Automated Development via MCP VBA Server")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
$Selection.TypeParagraph()
# Key metrics box
$Selection.Font.Size = 12
$Selection.Font.Italic = $false
$Selection.Font.Bold = $true
$Selection.Font.Color = $AccentColor
$Selection.ParagraphFormat.SpaceBefore = 80
$Selection.TypeText("Project Highlights")
$Selection.TypeParagraph()
$Selection.Font.Size = 11
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.ParagraphFormat.Alignment = 0 # Left align
$Selection.ParagraphFormat.LeftIndent = 100
$Selection.TypeText("• 915 Lines of Professional VBA Code")
$Selection.TypeParagraph()
$Selection.TypeText("• 7 Modular Components")
$Selection.TypeParagraph()
$Selection.TypeText("• 45% Development Time Reduction via Automation")
$Selection.TypeParagraph()
$Selection.TypeText("• Production-Ready Business Application")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
# Author info at bottom
$Selection.ParagraphFormat.LeftIndent = 0
$Selection.ParagraphFormat.Alignment = 1 # Center
$Selection.ParagraphFormat.SpaceBefore = 200
$Selection.Font.Size = 12
$Selection.Font.Bold = $true
$Selection.Font.Color = $DarkColor
$Selection.TypeText("Alexis Trouvé")
$Selection.TypeParagraph()
$Selection.Font.Size = 10
$Selection.Font.Bold = $false
$Selection.Font.Color = $AccentColor
$Selection.TypeText("alexistrouve.pro@gmail.com")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
$Selection.Font.Size = 9
$Selection.Font.Color = $DarkColor
$Selection.TypeText("Version 1.0 | January 2025")
$Selection.TypeParagraph()
# Page break
$Selection.InsertNewPage()
# ============================================================================
# TABLE OF CONTENTS
# ============================================================================
$Selection.Font.Name = "Segoe UI"
$Selection.Font.Size = 20
$Selection.Font.Bold = $true
$Selection.Font.Color = $DarkColor
$Selection.ParagraphFormat.Alignment = 0
$Selection.ParagraphFormat.SpaceBefore = 0
$Selection.ParagraphFormat.LeftIndent = 0
$Selection.TypeText("Table of Contents")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
# Insert TOC
$Range = $Selection.Range
$TOC = $Doc.TablesOfContents.Add($Range, $true, 1, 3, $true, "", $true, $true)
$Selection.TypeParagraph()
# Page break
$Selection.InsertNewPage()
# ============================================================================
# SECTION 1: EXECUTIVE SUMMARY
# ============================================================================
# Section header with background
$Selection.Font.Size = 18
$Selection.Font.Bold = $true
$Selection.Font.Color = 16777215 # White
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = $DarkColor
$Selection.ParagraphFormat.SpaceBefore = 0
$Selection.ParagraphFormat.SpaceAfter = 12
$Selection.ParagraphFormat.LeftIndent = 10
$Selection.Style = "Heading 1"
$Selection.TypeText(" 1. Executive Summary")
$Selection.TypeParagraph()
# Reset formatting
$Selection.Font.Size = 11
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = 16777215 # White
$Selection.ParagraphFormat.LeftIndent = 0
$Selection.ParagraphFormat.SpaceAfter = 6
$Selection.Style = "Normal"
$Selection.TypeText("TimeTrack Pro is a professional time tracking application built on Microsoft Access, showcasing advanced database design, VBA automation, and modern development practices. This project demonstrates the capability to deliver production-ready business applications through automated development workflows using the VBA MCP Server.")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
$Selection.Font.Bold = $true
$Selection.Font.Color = $AccentColor
$Selection.TypeText("Key Achievement:")
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.TypeText(" Complete application development (database structure, business logic, queries, and VBA modules) automated via MCP (Model Context Protocol) integration, demonstrating cutting-edge AI-assisted development capabilities.")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
# Statistics table
$Selection.Font.Bold = $true
$Selection.Font.Size = 12
$Selection.Font.Color = $AccentColor
$Selection.TypeText("Project Statistics")
$Selection.TypeParagraph()
$Selection.Font.Bold = $false
$Selection.Font.Size = 11
$Table = $Doc.Tables.Add($Selection.Range, 7, 2)
$Table.Style = "Grid Table 4 - Accent 1"
$Table.ApplyStyleHeadingRows = $true
# Header row
$Table.Cell(1, 1).Range.Text = "Metric"
$Table.Cell(1, 2).Range.Text = "Value"
# Data rows
$Table.Cell(2, 1).Range.Text = "Total VBA Lines"
$Table.Cell(2, 2).Range.Text = "915"
$Table.Cell(3, 1).Range.Text = "VBA Modules"
$Table.Cell(3, 2).Range.Text = "7"
$Table.Cell(4, 1).Range.Text = "Database Tables"
$Table.Cell(4, 2).Range.Text = "3"
$Table.Cell(5, 1).Range.Text = "Functions"
$Table.Cell(5, 2).Range.Text = "45+"
$Table.Cell(6, 1).Range.Text = "Development Time Saved"
$Table.Cell(6, 2).Range.Text = "45%"
$Table.Cell(7, 1).Range.Text = "Comment Ratio"
$Table.Cell(7, 2).Range.Text = "25%"
$Selection.EndKey(6) # End of document
$Selection.TypeParagraph()
$Selection.TypeParagraph()
# ============================================================================
# SECTION 2: PROJECT OVERVIEW
# ============================================================================
$Selection.Style = "Heading 1"
$Selection.Font.Size = 18
$Selection.Font.Bold = $true
$Selection.Font.Color = 16777215
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = $DarkColor
$Selection.ParagraphFormat.LeftIndent = 10
$Selection.TypeText(" 2. Project Overview")
$Selection.TypeParagraph()
$Selection.Style = "Normal"
$Selection.Font.Size = 11
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = 16777215
$Selection.ParagraphFormat.LeftIndent = 0
# Subsection: Purpose
$Selection.Style = "Heading 2"
$Selection.Font.Size = 14
$Selection.Font.Bold = $true
$Selection.Font.Color = $AccentColor
$Selection.TypeText("2.1 Purpose")
$Selection.TypeParagraph()
$Selection.Style = "Normal"
$Selection.Font.Size = 11
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.TypeText("TimeTrack Pro is a time management tool designed for freelancers, consultants, and small teams to:")
$Selection.TypeParagraph()
$Selection.ParagraphFormat.LeftIndent = 30
$Selection.TypeText("• Track billable hours across multiple clients and projects")
$Selection.TypeParagraph()
$Selection.TypeText("• Calculate revenue automatically based on hourly rates")
$Selection.TypeParagraph()
$Selection.TypeText("• Generate professional reports for invoicing and analysis")
$Selection.TypeParagraph()
$Selection.TypeText("• Maintain a complete audit trail of time entries")
$Selection.TypeParagraph()
$Selection.ParagraphFormat.LeftIndent = 0
$Selection.TypeParagraph()
# Subsection: Target Audience
$Selection.Style = "Heading 2"
$Selection.Font.Size = 14
$Selection.Font.Bold = $true
$Selection.Font.Color = $AccentColor
$Selection.TypeText("2.2 Target Audience")
$Selection.TypeParagraph()
$Selection.Style = "Normal"
$Selection.Font.Size = 11
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.ParagraphFormat.LeftIndent = 30
$Selection.Font.Bold = $true
$Selection.TypeText("Freelancers: ")
$Selection.Font.Bold = $false
$Selection.TypeText("Independent consultants tracking multiple client projects")
$Selection.TypeParagraph()
$Selection.Font.Bold = $true
$Selection.TypeText("Small Teams: ")
$Selection.Font.Bold = $false
$Selection.TypeText("Agencies managing client work and resource allocation")
$Selection.TypeParagraph()
$Selection.Font.Bold = $true
$Selection.TypeText("Consultants: ")
$Selection.Font.Bold = $false
$Selection.TypeText("Professional services requiring detailed time records")
$Selection.TypeParagraph()
$Selection.ParagraphFormat.LeftIndent = 0
$Selection.TypeParagraph()
# ============================================================================
# SECTION 3: DATABASE ARCHITECTURE
# ============================================================================
$Selection.Style = "Heading 1"
$Selection.Font.Size = 18
$Selection.Font.Bold = $true
$Selection.Font.Color = 16777215
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = $DarkColor
$Selection.ParagraphFormat.LeftIndent = 10
$Selection.TypeText(" 3. Database Architecture")
$Selection.TypeParagraph()
$Selection.Style = "Normal"
$Selection.Font.Size = 11
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = 16777215
$Selection.ParagraphFormat.LeftIndent = 0
$Selection.TypeText("The application uses a normalized relational database structure with three core tables:")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
# Table: tbl_Clients
$Selection.Style = "Heading 2"
$Selection.Font.Size = 14
$Selection.Font.Bold = $true
$Selection.Font.Color = $AccentColor
$Selection.TypeText("3.1 Table: tbl_Clients")
$Selection.TypeParagraph()
$Selection.Style = "Normal"
$Selection.Font.Size = 11
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.TypeText("Stores client information and contact details.")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
$TableClients = $Doc.Tables.Add($Selection.Range, 7, 4)
$TableClients.Style = "Grid Table 4 - Accent 1"
$TableClients.ApplyStyleHeadingRows = $true
$TableClients.Cell(1, 1).Range.Text = "Field"
$TableClients.Cell(1, 2).Range.Text = "Type"
$TableClients.Cell(1, 3).Range.Text = "Size"
$TableClients.Cell(1, 4).Range.Text = "Description"
$TableClients.Cell(2, 1).Range.Text = "ClientID"
$TableClients.Cell(2, 2).Range.Text = "AutoNumber"
$TableClients.Cell(2, 3).Range.Text = "Long"
$TableClients.Cell(2, 4).Range.Text = "Primary Key"
$TableClients.Cell(3, 1).Range.Text = "Nom"
$TableClients.Cell(3, 2).Range.Text = "Text"
$TableClients.Cell(3, 3).Range.Text = "100"
$TableClients.Cell(3, 4).Range.Text = "Client name (required)"
$TableClients.Cell(4, 1).Range.Text = "Email"
$TableClients.Cell(4, 2).Range.Text = "Text"
$TableClients.Cell(4, 3).Range.Text = "100"
$TableClients.Cell(4, 4).Range.Text = "Email address"
$TableClients.Cell(5, 1).Range.Text = "Telephone"
$TableClients.Cell(5, 2).Range.Text = "Text"
$TableClients.Cell(5, 3).Range.Text = "20"
$TableClients.Cell(5, 4).Range.Text = "Phone number"
$TableClients.Cell(6, 1).Range.Text = "Notes"
$TableClients.Cell(6, 2).Range.Text = "Memo"
$TableClients.Cell(6, 3).Range.Text = "-"
$TableClients.Cell(6, 4).Range.Text = "Additional notes"
$TableClients.Cell(7, 1).Range.Text = "DateCreation"
$TableClients.Cell(7, 2).Range.Text = "DateTime"
$TableClients.Cell(7, 3).Range.Text = "-"
$TableClients.Cell(7, 4).Range.Text = "Record creation timestamp"
$Selection.EndKey(6)
$Selection.TypeParagraph()
$Selection.TypeParagraph()
# ============================================================================
# SECTION 4: VBA MODULES
# ============================================================================
$Selection.Style = "Heading 1"
$Selection.Font.Size = 18
$Selection.Font.Bold = $true
$Selection.Font.Color = 16777215
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = $DarkColor
$Selection.ParagraphFormat.LeftIndent = 10
$Selection.TypeText(" 4. VBA Architecture")
$Selection.TypeParagraph()
$Selection.Style = "Normal"
$Selection.Font.Size = 11
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = 16777215
$Selection.ParagraphFormat.LeftIndent = 0
$Selection.TypeText("The application uses a modular VBA architecture with 7 core modules totaling 915 lines of code:")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
$TableModules = $Doc.Tables.Add($Selection.Range, 8, 3)
$TableModules.Style = "Grid Table 4 - Accent 1"
$TableModules.ApplyStyleHeadingRows = $true
$TableModules.Cell(1, 1).Range.Text = "Module"
$TableModules.Cell(1, 2).Range.Text = "Purpose"
$TableModules.Cell(1, 3).Range.Text = "LOC"
$TableModules.Cell(2, 1).Range.Text = "mod_Config"
$TableModules.Cell(2, 2).Range.Text = "Application configuration and constants"
$TableModules.Cell(2, 3).Range.Text = "80"
$TableModules.Cell(3, 1).Range.Text = "mod_Navigation"
$TableModules.Cell(3, 2).Range.Text = "Form navigation and UI flow control"
$TableModules.Cell(3, 3).Range.Text = "120"
$TableModules.Cell(4, 1).Range.Text = "mod_DataAccess"
$TableModules.Cell(4, 2).Range.Text = "CRUD operations and database layer"
$TableModules.Cell(4, 3).Range.Text = "200"
$TableModules.Cell(5, 1).Range.Text = "mod_Calculs"
$TableModules.Cell(5, 2).Range.Text = "Business logic and calculations"
$TableModules.Cell(5, 3).Range.Text = "150"
$TableModules.Cell(6, 1).Range.Text = "mod_Export"
$TableModules.Cell(6, 2).Range.Text = "Report generation and export"
$TableModules.Cell(6, 3).Range.Text = "120"
$TableModules.Cell(7, 1).Range.Text = "mod_Utils"
$TableModules.Cell(7, 2).Range.Text = "Helper functions and validation"
$TableModules.Cell(7, 3).Range.Text = "100"
$TableModules.Cell(8, 1).Range.Text = "mod_FormBuilder"
$TableModules.Cell(8, 2).Range.Text = "Automated form creation (dev only)"
$TableModules.Cell(8, 3).Range.Text = "145"
$Selection.EndKey(6)
$Selection.TypeParagraph()
$Selection.TypeParagraph()
# ============================================================================
# SECTION 5: MCP VBA AUTOMATION
# ============================================================================
$Selection.Style = "Heading 1"
$Selection.Font.Size = 18
$Selection.Font.Bold = $true
$Selection.Font.Color = 16777215
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = $DarkColor
$Selection.ParagraphFormat.LeftIndent = 10
$Selection.TypeText(" 5. MCP VBA Server Automation")
$Selection.TypeParagraph()
$Selection.Style = "Normal"
$Selection.Font.Size = 11
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = 16777215
$Selection.ParagraphFormat.LeftIndent = 0
$Selection.TypeText("This project showcases advanced automation using the VBA MCP Server (Model Context Protocol), enabling AI-assisted development of Access applications.")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
# Development metrics
$Selection.Style = "Heading 2"
$Selection.Font.Size = 14
$Selection.Font.Bold = $true
$Selection.Font.Color = $AccentColor
$Selection.TypeText("5.1 Development Efficiency")
$Selection.TypeParagraph()
$Selection.Style = "Normal"
$Selection.Font.Size = 11
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$TableDev = $Doc.Tables.Add($Selection.Range, 7, 4)
$TableDev.Style = "Grid Table 4 - Accent 1"
$TableDev.ApplyStyleHeadingRows = $true
$TableDev.Cell(1, 1).Range.Text = "Phase"
$TableDev.Cell(1, 2).Range.Text = "Estimated"
$TableDev.Cell(1, 3).Range.Text = "Actual"
$TableDev.Cell(1, 4).Range.Text = "Method"
$TableDev.Cell(2, 1).Range.Text = "Database Design"
$TableDev.Cell(2, 2).Range.Text = "1h"
$TableDev.Cell(2, 3).Range.Text = "0.5h"
$TableDev.Cell(2, 4).Range.Text = "MCP Automated"
$TableDev.Cell(3, 1).Range.Text = "Test Data"
$TableDev.Cell(3, 2).Range.Text = "30min"
$TableDev.Cell(3, 3).Range.Text = "15min"
$TableDev.Cell(3, 4).Range.Text = "MCP Automated"
$TableDev.Cell(4, 1).Range.Text = "VBA Modules"
$TableDev.Cell(4, 2).Range.Text = "3h"
$TableDev.Cell(4, 3).Range.Text = "1h"
$TableDev.Cell(4, 4).Range.Text = "MCP Automated"
$TableDev.Cell(5, 1).Range.Text = "SQL Queries"
$TableDev.Cell(5, 2).Range.Text = "30min"
$TableDev.Cell(5, 3).Range.Text = "20min"
$TableDev.Cell(5, 4).Range.Text = "MCP Automated"
$TableDev.Cell(6, 1).Range.Text = "Forms"
$TableDev.Cell(6, 2).Range.Text = "2h"
$TableDev.Cell(6, 3).Range.Text = "1h"
$TableDev.Cell(6, 4).Range.Text = "Script + Manual"
$TableDev.Cell(7, 1).Range.Text = "Testing & Docs"
$TableDev.Cell(7, 2).Range.Text = "2h"
$TableDev.Cell(7, 3).Range.Text = "2h"
$TableDev.Cell(7, 4).Range.Text = "Manual"
$Selection.EndKey(6)
$Selection.TypeParagraph()
$Selection.TypeParagraph()
# Highlight box
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = 15132390 # Light blue
$Selection.ParagraphFormat.LeftIndent = 20
$Selection.ParagraphFormat.RightIndent = 20
$Selection.Font.Bold = $true
$Selection.Font.Size = 12
$Selection.Font.Color = $DarkColor
$Selection.TypeText("Development Efficiency: 45% time reduction through automation")
$Selection.TypeParagraph()
$Selection.Font.Bold = $false
$Selection.Font.Size = 11
$Selection.TypeText("Total estimated: 9 hours | Actual: ~5 hours")
$Selection.TypeParagraph()
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = 16777215
$Selection.ParagraphFormat.LeftIndent = 0
$Selection.ParagraphFormat.RightIndent = 0
$Selection.TypeParagraph()
# ============================================================================
# SECTION 6: PROFESSIONAL SERVICES
# ============================================================================
$Selection.Style = "Heading 1"
$Selection.Font.Size = 18
$Selection.Font.Bold = $true
$Selection.Font.Color = 16777215
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = $DarkColor
$Selection.ParagraphFormat.LeftIndent = 10
$Selection.TypeText(" 6. Professional Services Available")
$Selection.TypeParagraph()
$Selection.Style = "Normal"
$Selection.Font.Size = 11
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = 16777215
$Selection.ParagraphFormat.LeftIndent = 0
$Selection.TypeText("This project demonstrates expertise in the following areas:")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
$Selection.ParagraphFormat.LeftIndent = 30
$Selection.Font.Bold = $true
$Selection.Font.Color = $AccentColor
$Selection.TypeText("• Microsoft Access Development")
$Selection.TypeParagraph()
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.ParagraphFormat.LeftIndent = 50
$Selection.TypeText("Forms, reports, VBA automation, and SQL optimization")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
$Selection.ParagraphFormat.LeftIndent = 30
$Selection.Font.Bold = $true
$Selection.Font.Color = $AccentColor
$Selection.TypeText("• Database Design & Architecture")
$Selection.TypeParagraph()
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.ParagraphFormat.LeftIndent = 50
$Selection.TypeText("Normalization, indexing, referential integrity, and performance tuning")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
$Selection.ParagraphFormat.LeftIndent = 30
$Selection.Font.Bold = $true
$Selection.Font.Color = $AccentColor
$Selection.TypeText("• Business Application Development")
$Selection.TypeParagraph()
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.ParagraphFormat.LeftIndent = 50
$Selection.TypeText("Requirements analysis, UX design, testing, and deployment")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
$Selection.ParagraphFormat.LeftIndent = 30
$Selection.Font.Bold = $true
$Selection.Font.Color = $AccentColor
$Selection.TypeText("• Process Automation")
$Selection.TypeParagraph()
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.ParagraphFormat.LeftIndent = 50
$Selection.TypeText("VBA macros, AI-assisted development (MCP), workflow optimization")
$Selection.TypeParagraph()
$Selection.TypeParagraph()
$Selection.ParagraphFormat.LeftIndent = 30
$Selection.Font.Bold = $true
$Selection.Font.Color = $AccentColor
$Selection.TypeText("• Legacy System Modernization")
$Selection.TypeParagraph()
$Selection.Font.Bold = $false
$Selection.Font.Color = $DarkColor
$Selection.ParagraphFormat.LeftIndent = 50
$Selection.TypeText("Access to SQL Server migration, web application conversion")
$Selection.TypeParagraph()
$Selection.ParagraphFormat.LeftIndent = 0
$Selection.TypeParagraph()
$Selection.TypeParagraph()
# Contact box
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = $DarkColor
$Selection.ParagraphFormat.LeftIndent = 40
$Selection.ParagraphFormat.RightIndent = 40
$Selection.ParagraphFormat.SpaceBefore = 12
$Selection.ParagraphFormat.SpaceAfter = 12
$Selection.Font.Bold = $true
$Selection.Font.Size = 14
$Selection.Font.Color = 16777215
$Selection.ParagraphFormat.Alignment = 1
$Selection.TypeText("Contact Information")
$Selection.TypeParagraph()
$Selection.Font.Bold = $false
$Selection.Font.Size = 11
$Selection.Font.Color = 16777215
$Selection.TypeText("Alexis Trouvé")
$Selection.TypeParagraph()
$Selection.TypeText("alexistrouve.pro@gmail.com")
$Selection.TypeParagraph()
$Selection.Font.Italic = $true
$Selection.Font.Size = 10
$Selection.TypeText("Response time: Within 24 hours")
$Selection.TypeParagraph()
$Selection.ParagraphFormat.Shading.BackgroundPatternColor = 16777215
$Selection.ParagraphFormat.LeftIndent = 0
$Selection.ParagraphFormat.RightIndent = 0
$Selection.ParagraphFormat.Alignment = 0
$Selection.Font.Italic = $false
# ============================================================================
# UPDATE TABLE OF CONTENTS
# ============================================================================
Write-Host "Updating table of contents..." -ForegroundColor Yellow
$TOC.Update()
# ============================================================================
# ADD HEADERS AND FOOTERS
# ============================================================================
Write-Host "Adding headers and footers..." -ForegroundColor Yellow
$Section = $Doc.Sections.Item(1)
$Header = $Section.Headers.Item(1)
$Footer = $Section.Footers.Item(1)
# Header
$Header.Range.Text = "TimeTrack Pro - Technical Reference"
$Header.Range.Font.Size = 9
$Header.Range.Font.Color = 8421504 # Grey
$Header.Range.ParagraphFormat.Alignment = 2 # Right align
# Footer
$Footer.Range.Text = "Page "
$Footer.Range.Font.Size = 9
$Footer.Range.Font.Color = 8421504
$Footer.Range.ParagraphFormat.Alignment = 1 # Center
$Field = $Footer.Range.Fields.Add($Footer.Range, 26) # wdFieldPage
$Footer.Range.InsertAfter(" | Alexis Trouvé | 2025")
# ============================================================================
# SAVE AS PDF
# ============================================================================
Write-Host "Saving as PDF..." -ForegroundColor Yellow
$Doc.SaveAs([ref]$OutputPath, [ref]17)
Write-Host "Closing document..." -ForegroundColor Yellow
$Doc.Close()
$Word.Quit()
# Cleanup
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Selection) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Doc) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Word) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
Write-Host ""
Write-Host "SUCCESS! Professional PDF created:" -ForegroundColor Green
Write-Host $OutputPath -ForegroundColor Cyan
Write-Host ""
} catch {
Write-Host ""
Write-Host "ERROR:" -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Red
if ($Word) {
$Word.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Word) | Out-Null
}
exit 1
}

View File

@ -0,0 +1,85 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
accessApp.Visible = True
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
WScript.Echo "=== Deleting standard modules ==="
' Supprimer les modules standards Form_*
Dim modulesToDelete
modulesToDelete = Array("Form_frm_Accueil", "Form_frm_Clients", "Form_frm_Projets", "Form_frm_SaisieTemps", "Form_frm_Historique")
Dim i, comp
For i = LBound(modulesToDelete) To UBound(modulesToDelete)
For Each comp In vbProj.VBComponents
If comp.Name = modulesToDelete(i) And comp.Type = 1 Then ' 1 = Standard Module
vbProj.VBComponents.Remove comp
WScript.Echo "Deleted: " & modulesToDelete(i)
Exit For
End If
Next
Next
WScript.Sleep 1000
WScript.Echo ""
WScript.Echo "=== Creating form modules ==="
' Recréer les modules de formulaire
Dim formNames
formNames = Array("frm_Accueil", "frm_Clients", "frm_Projets", "frm_SaisieTemps", "frm_Historique")
For i = LBound(formNames) To UBound(formNames)
WScript.Echo "Processing " & formNames(i) & "..."
' Ouvrir en mode Design VISIBLE
accessApp.DoCmd.OpenForm formNames(i), 2 ' acDesign, pas hidden
WScript.Sleep 1000
' Essayer de créer le module
On Error Resume Next
Err.Clear
' Méthode 1: Via HasModule
accessApp.Forms(formNames(i)).HasModule = True
If Err.Number = 0 Then
WScript.Echo " -> Created via HasModule"
Else
WScript.Echo " -> HasModule failed: " & Err.Description
Err.Clear
' Méthode 2: Via DoCmd ViewCode
accessApp.DoCmd.OpenForm formNames(i), 2
WScript.Sleep 500
accessApp.DoCmd.RunCommand 401 ' acCmdViewCode - ouvre l'éditeur VBA du formulaire
WScript.Sleep 1000
WScript.Echo " -> Opened code view"
End If
' Fermer le formulaire
accessApp.DoCmd.Close 2, formNames(i), 1 ' acSaveYes
WScript.Sleep 500
Next
WScript.Sleep 1000
WScript.Echo ""
WScript.Echo "=== Verification ==="
For Each comp In vbProj.VBComponents
WScript.Echo comp.Name & " - Type: " & comp.Type
Next
WScript.Echo ""
WScript.Echo "Done! Press OK to close Access."
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing

49
delete_by_name.vbs Normal file
View File

@ -0,0 +1,49 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
WScript.Echo "=== Deleting specific fake modules ==="
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
' Supprimer un par un par nom
Dim modulesToDelete
modulesToDelete = Array("Form_frm_Accueil", "Form_frm_Clients", "Form_frm_Projets", "Form_frm_Historique")
Dim i
For i = LBound(modulesToDelete) To UBound(modulesToDelete)
Dim comp
Set comp = Nothing
' Trouver le module
Dim c
For Each c In vbProj.VBComponents
If c.Name = modulesToDelete(i) Then
Set comp = c
Exit For
End If
Next
' Supprimer si trouve
If Not comp Is Nothing Then
WScript.Echo "Deleting: " & comp.Name & " (Type " & comp.Type & ")"
vbProj.VBComponents.Remove comp
WScript.Echo " -> Deleted!"
Else
WScript.Echo "Not found: " & modulesToDelete(i)
End If
Next
WScript.Echo ""
WScript.Echo "=== Remaining modules ==="
For Each c In vbProj.VBComponents
WScript.Echo c.Name & " - Type: " & c.Type
Next
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing

25
delete_fake_modules.vbs Normal file
View File

@ -0,0 +1,25 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
WScript.Echo "=== Deleting fake Form_* Type 1 modules ==="
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
Dim comp
For Each comp In vbProj.VBComponents
If Left(comp.Name, 5) = "Form_" And comp.Type = 1 Then ' Type 1 = Standard Module
WScript.Echo "Deleting fake module: " & comp.Name & " (Type " & comp.Type & ")"
vbProj.VBComponents.Remove comp
End If
Next
WScript.Echo "Done! All fake modules deleted."
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing

25
delete_form_modules.vbs Normal file
View File

@ -0,0 +1,25 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
WScript.Echo "=== Deleting Form_* modules ==="
Dim comp
For Each comp In vbProj.VBComponents
If Left(comp.Name, 5) = "Form_" And comp.Type = 1 Then ' Type 1 = Standard Module
WScript.Echo "Deleting: " & comp.Name
vbProj.VBComponents.Remove comp
End If
Next
WScript.Echo "Done!"
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing

59
enable_form_modules.vbs Normal file
View File

@ -0,0 +1,59 @@
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
accessApp.Visible = True
Dim formNames
formNames = Array("frm_Accueil", "frm_Clients", "frm_Projets", "frm_SaisieTemps", "frm_Historique")
Dim i
For i = LBound(formNames) To UBound(formNames)
On Error Resume Next
' Ouvrir en mode Design
accessApp.DoCmd.OpenForm formNames(i), 2
WScript.Sleep 1000
' Acceder au module VBA du projet
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
' Verifier si le module existe deja
Dim moduleExists
moduleExists = False
Dim comp
For Each comp In vbProj.VBComponents
If comp.Name = "Form_" & formNames(i) Then
moduleExists = True
Exit For
End If
Next
If Not moduleExists Then
' Forcer la creation du module en ajoutant du code VBA
Dim vbComp
Set vbComp = vbProj.VBComponents.Add(100) ' 100 = vbext_ct_MSForm (form module)
vbComp.Name = "Form_" & formNames(i)
vbComp.CodeModule.AddFromString "Option Compare Database" & vbCrLf & "Option Explicit"
WScript.Echo "Created module for: " & formNames(i)
Else
WScript.Echo "Module already exists for: " & formNames(i)
End If
accessApp.DoCmd.Close 2, formNames(i), 1
If Err.Number = 0 Then
WScript.Echo "Module enabled for: " & formNames(i)
Else
WScript.Echo "Error for " & formNames(i) & ": " & Err.Description
Err.Clear
End If
Next
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing
WScript.Echo "All done!"

48
enable_modules_dao.vbs Normal file
View File

@ -0,0 +1,48 @@
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
' Execute VBA code to enable modules using DAO
Dim vbaCode
vbaCode = "Public Sub EnableModules()" & vbCrLf & _
"Dim db As DAO.Database" & vbCrLf & _
"Set db = CurrentDb" & vbCrLf & _
"Dim doc As DAO.Document" & vbCrLf & _
"Dim formNames As Variant" & vbCrLf & _
"formNames = Array(""frm_Accueil"", ""frm_Clients"", ""frm_Projets"", ""frm_SaisieTemps"", ""frm_Historique"")" & vbCrLf & _
"Dim i As Integer" & vbCrLf & _
"For i = LBound(formNames) To UBound(formNames)" & vbCrLf & _
" Set doc = db.Containers(""Forms"").Documents(formNames(i))" & vbCrLf & _
" doc.Properties(""HasModule"") = True" & vbCrLf & _
" Debug.Print ""Enabled: "" & formNames(i)" & vbCrLf & _
"Next i" & vbCrLf & _
"MsgBox ""All modules enabled!""" & vbCrLf & _
"End Sub"
' Add temp module
On Error Resume Next
accessApp.DoCmd.DeleteObject 5, "tempModuleEnabler" ' 5 = acModule
Err.Clear
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
Dim vbComp
Set vbComp = vbProj.VBComponents.Add(1) ' 1 = vbext_ct_StdModule
vbComp.Name = "tempModuleEnabler"
vbComp.CodeModule.AddFromString vbaCode
WScript.Sleep 1000
' Run the macro
accessApp.Run "tempModuleEnabler.EnableModules"
WScript.Sleep 1000
' Cleanup
accessApp.DoCmd.DeleteObject 5, "tempModuleEnabler"
accessApp.CloseCurrentDatabase
accessApp.Quit
WScript.Echo "Done!"

15
execute_fix.vbs Normal file
View File

@ -0,0 +1,15 @@
Dim accessApp
Set accessApp = GetObject(, "Access.Application")
' Executer le code directement via VBE
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
' Trouver le module
Dim vbComp
Set vbComp = vbProj.VBComponents("mod_FixFormBindings")
' Executer la procedure
accessApp.DoCmd.RunMacro "mod_FixFormBindings.FixAllFormBindings"
WScript.Echo "Done!"

81
final_cleanup.vbs Normal file
View File

@ -0,0 +1,81 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
WScript.Echo "=== Final cleanup: Direct VBProject manipulation ==="
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
' List all components first
WScript.Echo ""
WScript.Echo "Before cleanup:"
Dim c
For Each c In vbProj.VBComponents
If Left(c.Name, 4) = "OLD_" Or Left(c.Name, 5) = "Form_" Then
WScript.Echo " " & c.Name & " (Type " & c.Type & ")"
End If
Next
' Try to delete OLD modules one by one
WScript.Echo ""
WScript.Echo "Attempting removal..."
Dim oldModules
oldModules = Array("OLD_Form_frm_Accueil", "OLD_Form_frm_Clients", "OLD_Form_frm_Projets", "OLD_Form_frm_Historique")
Dim i, comp
For i = 0 To UBound(oldModules)
WScript.Echo "Looking for: " & oldModules(i)
Dim removed
removed = False
On Error Resume Next
' Try multiple times if needed
Dim attempts
For attempts = 1 To 5
For Each comp In vbProj.VBComponents
If comp.Name = oldModules(i) Then
vbProj.VBComponents.Remove comp
If Err.Number = 0 Then
WScript.Echo " Removed on attempt " & attempts
removed = True
Exit For
End If
End If
Next
If removed Then Exit For
Next
If Not removed Then
WScript.Echo " Could not remove (will try renaming instead)"
' Try renaming
For Each comp In vbProj.VBComponents
If comp.Name = oldModules(i) Then
On Error Resume Next
comp.Name = "DELETED_" & oldModules(i)
WScript.Echo " Renamed to: DELETED_" & oldModules(i)
Exit For
End If
Next
End If
Next
WScript.Echo ""
WScript.Echo "After cleanup:"
For Each c In vbProj.VBComponents
If Left(c.Name, 4) = "OLD_" Or Left(c.Name, 5) = "Form_" Or Left(c.Name, 8) = "DELETED_" Then
WScript.Echo " " & c.Name & " (Type " & c.Type & ")"
End If
Next
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing
WScript.Echo ""
WScript.Echo "Done!"

52
fix_all_bindings.vbs Normal file
View File

@ -0,0 +1,52 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
accessApp.Visible = False
WScript.Echo "Fixing frm_Clients..."
accessApp.DoCmd.OpenForm "frm_Clients", 2 ' acDesign
accessApp.Forms("frm_Clients").RecordSource = "tbl_Clients"
accessApp.Forms("frm_Clients").Controls("txtNom").ControlSource = "Nom"
accessApp.Forms("frm_Clients").Controls("txtEmail").ControlSource = "Email"
accessApp.Forms("frm_Clients").Controls("txtTelephone").ControlSource = "Telephone"
accessApp.Forms("frm_Clients").Controls("txtNotes").ControlSource = "Notes"
accessApp.DoCmd.Close 2, "frm_Clients", 1
WScript.Echo "frm_Clients done"
WScript.Sleep 500
WScript.Echo "Fixing frm_Projets..."
accessApp.DoCmd.OpenForm "frm_Projets", 2
accessApp.Forms("frm_Projets").RecordSource = "tbl_Projets"
accessApp.Forms("frm_Projets").Controls("cboClient").ControlSource = "ClientID"
accessApp.Forms("frm_Projets").Controls("txtNom").ControlSource = "Nom"
accessApp.Forms("frm_Projets").Controls("txtDescription").ControlSource = "Description"
accessApp.Forms("frm_Projets").Controls("txtTauxHoraire").ControlSource = "TauxHoraire"
' Note: chkActif might not exist
On Error Resume Next
accessApp.Forms("frm_Projets").Controls("chkActif").ControlSource = "Actif"
On Error Goto 0
accessApp.DoCmd.Close 2, "frm_Projets", 1
WScript.Echo "frm_Projets done"
WScript.Sleep 500
WScript.Echo "Fixing frm_SaisieTemps..."
accessApp.DoCmd.OpenForm "frm_SaisieTemps", 2
accessApp.Forms("frm_SaisieTemps").RecordSource = "tbl_Temps"
accessApp.Forms("frm_SaisieTemps").Controls("cboProjet").ControlSource = "ProjetID"
accessApp.Forms("frm_SaisieTemps").Controls("txtDate").ControlSource = "Date"
accessApp.Forms("frm_SaisieTemps").Controls("txtDuree").ControlSource = "Duree"
accessApp.Forms("frm_SaisieTemps").Controls("txtDescription").ControlSource = "Description"
accessApp.DoCmd.Close 2, "frm_SaisieTemps", 1
WScript.Echo "frm_SaisieTemps done"
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing
WScript.Echo "All forms fixed successfully!"

22
fix_bindings_direct.vbs Normal file
View File

@ -0,0 +1,22 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
' Ouvrir la base (sans fermer la session existante)
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb", True
' Executer directement le code VBA via DoCmd.RunCode
accessApp.DoCmd.RunCode "mod_FixFormBindings.FixAllFormBindings"
If Err.Number <> 0 Then
WScript.Echo "Error: " & Err.Number & " - " & Err.Description
Else
WScript.Echo "Success!"
End If
' Fermer
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing

49
fix_form_bindings.vbs Normal file
View File

@ -0,0 +1,49 @@
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
accessApp.Visible = False
On Error Resume Next
' Fix frm_Clients
accessApp.DoCmd.OpenForm "frm_Clients", 2, , , , 1 ' acDesign, Hidden
WScript.Sleep 500
accessApp.Forms("frm_Clients").RecordSource = "tbl_Clients"
accessApp.Forms("frm_Clients").Controls("txtNom").ControlSource = "Nom"
accessApp.Forms("frm_Clients").Controls("txtEmail").ControlSource = "Email"
accessApp.Forms("frm_Clients").Controls("txtTelephone").ControlSource = "Telephone"
accessApp.Forms("frm_Clients").Controls("txtNotes").ControlSource = "Notes"
accessApp.DoCmd.Close 2, "frm_Clients", 1
If Err.Number = 0 Then WScript.Echo "frm_Clients fixed" Else WScript.Echo "Error frm_Clients: " & Err.Description
Err.Clear
' Fix frm_Projets
accessApp.DoCmd.OpenForm "frm_Projets", 2, , , , 1
WScript.Sleep 500
accessApp.Forms("frm_Projets").RecordSource = "tbl_Projets"
accessApp.Forms("frm_Projets").Controls("cboClient").ControlSource = "ClientID"
accessApp.Forms("frm_Projets").Controls("txtNom").ControlSource = "Nom"
accessApp.Forms("frm_Projets").Controls("txtDescription").ControlSource = "Description"
accessApp.Forms("frm_Projets").Controls("txtTauxHoraire").ControlSource = "TauxHoraire"
accessApp.Forms("frm_Projets").Controls("chkActif").ControlSource = "Actif"
accessApp.DoCmd.Close 2, "frm_Projets", 1
If Err.Number = 0 Then WScript.Echo "frm_Projets fixed" Else WScript.Echo "Error frm_Projets: " & Err.Description
Err.Clear
' Fix frm_SaisieTemps
accessApp.DoCmd.OpenForm "frm_SaisieTemps", 2, , , , 1
WScript.Sleep 500
accessApp.Forms("frm_SaisieTemps").RecordSource = "tbl_Temps"
accessApp.Forms("frm_SaisieTemps").Controls("cboProjet").ControlSource = "ProjetID"
accessApp.Forms("frm_SaisieTemps").Controls("txtDate").ControlSource = "Date"
accessApp.Forms("frm_SaisieTemps").Controls("txtDuree").ControlSource = "Duree"
accessApp.Forms("frm_SaisieTemps").Controls("txtDescription").ControlSource = "Description"
accessApp.DoCmd.Close 2, "frm_SaisieTemps", 1
If Err.Number = 0 Then WScript.Echo "frm_SaisieTemps fixed" Else WScript.Echo "Error frm_SaisieTemps: " & Err.Description
Err.Clear
accessApp.CloseCurrentDatabase
accessApp.Quit
WScript.Echo "All forms fixed!"

41
fix_saisietemps.vbs Normal file
View File

@ -0,0 +1,41 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
accessApp.Visible = False
WScript.Echo "Fixing frm_SaisieTemps..."
' Ouvrir en mode Design
accessApp.DoCmd.OpenForm "frm_SaisieTemps", 2 ' 2 = acDesign
WScript.Sleep 1000
' Fixer les bindings
accessApp.Forms("frm_SaisieTemps").RecordSource = "tbl_Temps"
WScript.Sleep 200
accessApp.Forms("frm_SaisieTemps").Controls("cboProjet").ControlSource = "ProjetID"
WScript.Sleep 200
accessApp.Forms("frm_SaisieTemps").Controls("txtDate").ControlSource = "Date"
WScript.Sleep 200
accessApp.Forms("frm_SaisieTemps").Controls("txtDuree").ControlSource = "Duree"
WScript.Sleep 200
accessApp.Forms("frm_SaisieTemps").Controls("txtDescription").ControlSource = "Description"
WScript.Sleep 200
' Sauvegarder et fermer
accessApp.DoCmd.Close 2, "frm_SaisieTemps", 1 ' 1 = acSaveYes
If Err.Number = 0 Then
WScript.Echo "frm_SaisieTemps fixed successfully!"
Else
WScript.Echo "Error: " & Err.Number & " - " & Err.Description
End If
' Cleanup
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing
WScript.Echo "Done!"

65
force_delete_old.vbs Normal file
View File

@ -0,0 +1,65 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
WScript.Echo "=== Force delete OLD_* modules ==="
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
Dim toDelete
toDelete = Array("OLD_Form_frm_Accueil", "OLD_Form_frm_Clients", "OLD_Form_frm_Projets", "OLD_Form_frm_Historique")
Dim i
For i = LBound(toDelete) To UBound(toDelete)
WScript.Echo "Looking for: " & toDelete(i)
Dim found
found = False
Dim c
For Each c In vbProj.VBComponents
If c.Name = toDelete(i) Then
found = True
WScript.Echo " Found! Type: " & c.Type
' Try multiple times
Dim attempts
For attempts = 1 To 3
On Error Resume Next
vbProj.VBComponents.Remove c
If Err.Number = 0 Then
WScript.Echo " Attempt " & attempts & ": SUCCESS"
Exit For
Else
WScript.Echo " Attempt " & attempts & ": Error " & Err.Number & " - " & Err.Description
Err.Clear
End If
Next
Exit For
End If
Next
If Not found Then
WScript.Echo " Not found!"
End If
Next
WScript.Echo ""
WScript.Echo "=== All OLD modules check ==="
For Each c In vbProj.VBComponents
If Left(c.Name, 4) = "OLD_" Then
WScript.Echo "Still exists: " & c.Name
End If
Next
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing
WScript.Echo "Done!"

953
generate_complete_pdf.py Normal file
View File

@ -0,0 +1,953 @@
#!/usr/bin/env python3
"""
Professional PDF Generator for TimeTrack Pro - Complete Version
Creates comprehensive technical documentation
"""
from reportlab.lib import colors
from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, PageBreak, Table, TableStyle,
KeepTogether, HRFlowable
)
from reportlab.pdfgen import canvas
# Professional colors
PRIMARY = colors.HexColor('#2C3E50')
ACCENT = colors.HexColor('#2980B9')
LIGHT_ACCENT = colors.HexColor('#3498DB')
SUCCESS = colors.HexColor('#27AE60')
GREY = colors.HexColor('#7F8C8D')
LIGHT_GREY = colors.HexColor('#ECF0F1')
OUTPUT = r"C:\Users\alexi\Documents\projects\timetrack-pro\TimeTrack_Pro_Complete_Documentation.pdf"
class NumberedCanvas(canvas.Canvas):
def __init__(self, *args, **kwargs):
canvas.Canvas.__init__(self, *args, **kwargs)
self._saved_page_states = []
def showPage(self):
self._saved_page_states.append(dict(self.__dict__))
self._startPage()
def save(self):
num_pages = len(self._saved_page_states)
for state in self._saved_page_states:
self.__dict__.update(state)
self.draw_decorations(num_pages)
canvas.Canvas.showPage(self)
canvas.Canvas.save(self)
def draw_decorations(self, count):
self.saveState()
self.setFont('Helvetica', 9)
self.setFillColor(GREY)
# Page number
self.drawCentredString(letter[0]/2, 0.5*inch, f"Page {self._pageNumber} of {count}")
# Header (skip page 1)
if self._pageNumber > 1:
self.drawString(0.75*inch, letter[1]-0.5*inch, "TimeTrack Pro - Technical Reference")
self.drawRightString(letter[0]-0.75*inch, letter[1]-0.5*inch, "Alexis Trouvé | 2025")
self.restoreState()
def get_styles():
"""Get custom styles"""
s = getSampleStyleSheet()
# Add custom styles with unique names
s.add(ParagraphStyle(
name='CTitle', parent=s['Heading1'], fontSize=48, textColor=PRIMARY,
spaceAfter=20, alignment=TA_CENTER, fontName='Helvetica-Bold'))
s.add(ParagraphStyle(
name='CSubtitle', parent=s['Normal'], fontSize=24, textColor=ACCENT,
spaceAfter=30, alignment=TA_CENTER))
s.add(ParagraphStyle(
name='SHead', parent=s['Heading1'], fontSize=20, textColor=colors.white,
backColor=PRIMARY, spaceAfter=16, spaceBefore=12, leftIndent=10,
fontName='Helvetica-Bold', leading=28))
s.add(ParagraphStyle(
name='SubHead', parent=s['Heading2'], fontSize=14, textColor=ACCENT,
spaceAfter=10, spaceBefore=12, fontName='Helvetica-Bold'))
s.add(ParagraphStyle(
name='Body', parent=s['Normal'], fontSize=11, textColor=PRIMARY,
alignment=TA_JUSTIFY, spaceAfter=8, leading=14))
s.add(ParagraphStyle(
name='Bull', parent=s['Normal'], fontSize=11, textColor=PRIMARY,
leftIndent=30, spaceAfter=6, leading=14))
s.add(ParagraphStyle(
name='CodeBlock', parent=s['Normal'], fontSize=9, textColor=PRIMARY,
fontName='Courier', leftIndent=20, backColor=LIGHT_GREY, spaceAfter=8))
return s
def build_pdf():
doc = SimpleDocTemplate(OUTPUT, pagesize=letter, rightMargin=0.75*inch,
leftMargin=0.75*inch, topMargin=1*inch,
bottomMargin=0.75*inch,
title="TimeTrack Pro Technical Reference",
author="Alexis Trouvé")
story = []
s = get_styles()
print("Building PDF sections...")
# ========== COVER PAGE ==========
print(" - Cover page")
story.append(Spacer(1, 1.5*inch))
story.append(Paragraph("TimeTrack Pro", s['CTitle']))
story.append(Spacer(1, 0.3*inch))
story.append(Paragraph("Technical & Functional Reference", s['CSubtitle']))
story.append(Spacer(1, 0.2*inch))
story.append(HRFlowable(width="70%", thickness=2, color=ACCENT,
spaceAfter=30, spaceBefore=10, hAlign='CENTER'))
desc = ParagraphStyle('CD', parent=s['Body'], fontSize=13, alignment=TA_CENTER,
fontName='Helvetica-Oblique')
story.append(Paragraph("Professional Time Tracking Application", desc))
story.append(Paragraph("Built with Microsoft Access & VBA", desc))
story.append(Paragraph("Automated Development via MCP VBA Server", desc))
story.append(Spacer(1, 0.5*inch))
# Highlights table
hl_data = [
['Project Highlights', ''],
['Total VBA Code', '915 Lines'],
['Modular Components', '7 Modules'],
['Database Tables', '3 Normalized Tables'],
['Public Functions', '45+ Functions'],
['Development Time Saved', '45% via Automation'],
['Code Quality', '25% Comment Ratio'],
]
hl_table = Table(hl_data, colWidths=[3*inch, 2*inch])
hl_table.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), PRIMARY),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('ALIGN', (0,0), (-1,0), 'CENTER'),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 14),
('BOTTOMPADDING', (0,0), (-1,0), 12),
('TOPPADDING', (0,0), (-1,0), 12),
('BACKGROUND', (0,1), (0,-1), LIGHT_GREY),
('FONTNAME', (0,1), (0,-1), 'Helvetica-Bold'),
('ALIGN', (1,1), (1,-1), 'RIGHT'),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('LEFTPADDING', (0,0), (-1,-1), 10),
('RIGHTPADDING', (0,0), (-1,-1), 10),
('TOPPADDING', (0,1), (-1,-1), 8),
('BOTTOMPADDING', (0,1), (-1,-1), 8),
]))
story.append(hl_table)
story.append(Spacer(1, 1*inch))
auth = ParagraphStyle('Auth', parent=s['Body'], fontSize=13, alignment=TA_CENTER,
fontName='Helvetica-Bold')
cont = ParagraphStyle('Cont', parent=s['Body'], fontSize=11, alignment=TA_CENTER,
textColor=ACCENT)
vers = ParagraphStyle('Vers', parent=s['Body'], fontSize=10, alignment=TA_CENTER,
textColor=GREY)
story.append(Paragraph("Alexis Trouvé", auth))
story.append(Spacer(1, 0.1*inch))
story.append(Paragraph("alexistrouve.pro@gmail.com", cont))
story.append(Paragraph('<link href="https://github.com/AlexisTrouve?tab=repositories">github.com/AlexisTrouve</link>', cont))
story.append(Spacer(1, 0.3*inch))
story.append(Paragraph("Version 1.0 | January 2025", vers))
story.append(PageBreak())
# ========== TABLE OF CONTENTS ==========
print(" - Table of contents")
story.append(Paragraph("Table of Contents", s['SHead']))
story.append(Spacer(1, 0.2*inch))
toc_items = [
"1. Executive Summary",
"2. Project Overview",
"3. Database Architecture",
"4. VBA Module Architecture",
"5. Functional Specifications",
"6. MCP VBA Server Automation",
"7. Use Cases & Applications",
"8. Installation & Deployment",
"9. Professional Services Available",
"10. Appendices & Resources"
]
for item in toc_items:
story.append(Paragraph(f"{item}", s['Bull']))
story.append(PageBreak())
# ========== SECTION 1 ==========
print(" - Section 1: Executive Summary")
story.append(Paragraph("1. Executive Summary", s['SHead']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph(
"""TimeTrack Pro is a professional time tracking application built on Microsoft Access,
showcasing advanced database design, VBA automation, and modern development practices.
This project demonstrates the capability to deliver production-ready business applications
through automated development workflows using the VBA MCP Server.""", s['Body']))
story.append(Spacer(1, 0.1*inch))
story.append(Paragraph(
"""<b><font color="#2980B9">Key Achievement:</font></b> Complete application development
(database structure, business logic, queries, and VBA modules) automated via MCP
(Model Context Protocol), demonstrating cutting-edge AI-assisted development.""", s['Body']))
story.append(Spacer(1, 0.2*inch))
story.append(Paragraph("1.1 Project Statistics", s['SubHead']))
stats = [
['Metric', 'Value', 'Description'],
['Total VBA Lines', '915', 'Professional, commented code'],
['VBA Modules', '7', 'Modular architecture'],
['Database Tables', '3', 'Normalized structure'],
['Public Functions', '45+', 'Reusable components'],
['Time Saved', '45%', 'Via MCP automation'],
['Comment Ratio', '25%', 'Well-documented'],
['Error Handling', '100%', 'All public functions'],
]
st = Table(stats, colWidths=[2*inch, 1.5*inch, 3*inch])
st.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), PRIMARY),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 11),
('BOTTOMPADDING', (0,0), (-1,0), 10),
('TOPPADDING', (0,0), (-1,0), 10),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('LEFTPADDING', (0,0), (-1,-1), 8),
('RIGHTPADDING', (0,0), (-1,-1), 8),
('TOPPADDING', (0,1), (-1,-1), 6),
('BOTTOMPADDING', (0,1), (-1,-1), 6),
]))
story.append(st)
story.append(Spacer(1, 0.2*inch))
story.append(Paragraph("1.2 Current Data", s['SubHead']))
usage = [
['Metric', 'Value'],
['Active Clients', '4'],
['Active Projects', '6'],
['Time Entries', '15+'],
['Hours Tracked', '58 hours'],
['Revenue Calculated', '€4,732.50'],
]
ut = Table(usage, colWidths=[3*inch, 2*inch])
ut.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), ACCENT),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 11),
('FONTNAME', (1,1), (1,-1), 'Helvetica-Bold'),
('FONTSIZE', (1,1), (1,-1), 12),
('TEXTCOLOR', (1,1), (1,-1), SUCCESS),
('ALIGN', (1,0), (1,-1), 'RIGHT'),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('LEFTPADDING', (0,0), (-1,-1), 10),
('RIGHTPADDING', (0,0), (-1,-1), 10),
('TOPPADDING', (0,0), (-1,-1), 8),
('BOTTOMPADDING', (0,0), (-1,-1), 8),
]))
story.append(ut)
story.append(PageBreak())
# ========== SECTION 2 ==========
print(" - Section 2: Project Overview")
story.append(Paragraph("2. Project Overview", s['SHead']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph("2.1 Purpose", s['SubHead']))
story.append(Paragraph("TimeTrack Pro is a time management tool designed for freelancers, consultants, and small teams to:", s['Body']))
for item in ["Track billable hours across multiple clients and projects",
"Calculate revenue automatically based on hourly rates",
"Generate professional reports for invoicing",
"Maintain complete audit trail of time entries"]:
story.append(Paragraph(f"{item}", s['Bull']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph("2.2 Target Audience", s['SubHead']))
aud = [
['Audience', 'Use Case'],
['Freelancers', 'Independent consultants tracking multiple client projects'],
['Small Teams', 'Agencies managing client work and resource allocation'],
['Consultants', 'Professional services requiring detailed time records'],
]
at = Table(aud, colWidths=[1.5*inch, 5*inch])
at.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), ACCENT),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('LEFTPADDING', (0,0), (-1,-1), 8),
('RIGHTPADDING', (0,0), (-1,-1), 8),
('TOPPADDING', (0,0), (-1,0), 10),
('BOTTOMPADDING', (0,0), (-1,0), 10),
('TOPPADDING', (0,1), (-1,-1), 8),
('BOTTOMPADDING', (0,1), (-1,-1), 8),
]))
story.append(at)
story.append(Spacer(1, 0.2*inch))
story.append(Paragraph("2.3 Technology Stack", s['SubHead']))
tech = [
['Component', 'Technology', 'Version'],
['Database', 'Microsoft Access', '2016+/Office 365'],
['Language', 'VBA', '7.1'],
['Automation', 'VBA MCP Server', 'v0.6.0+'],
['Export', 'PDF, Excel', 'Native'],
['Version Control', 'Git', '2.x'],
]
tt = Table(tech, colWidths=[2*inch, 2.2*inch, 2.3*inch])
tt.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), PRIMARY),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('LEFTPADDING', (0,0), (-1,-1), 8),
('RIGHTPADDING', (0,0), (-1,-1), 8),
('TOPPADDING', (0,0), (-1,0), 10),
('BOTTOMPADDING', (0,0), (-1,0), 10),
('TOPPADDING', (0,1), (-1,-1), 6),
('BOTTOMPADDING', (0,1), (-1,-1), 6),
]))
story.append(tt)
story.append(PageBreak())
# ========== SECTION 3 ==========
print(" - Section 3: Database Architecture")
story.append(Paragraph("3. Database Architecture", s['SHead']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph(
"The application uses a normalized relational database following third normal form (3NF). Three core tables with enforced referential integrity.", s['Body']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph("3.1 Entity Relationships", s['SubHead']))
erd = """
tbl_Clients (1) (N) tbl_Projets (1) (N) tbl_Temps
One Client has many Projects (1:N)
One Project has many Time Entries (1:N)
Referential integrity enforced with CASCADE
"""
story.append(Paragraph(erd, s['CodeBlock']))
story.append(Spacer(1, 0.2*inch))
story.append(Paragraph("3.2 Table: tbl_Clients", s['SubHead']))
cl = [
['Field', 'Type', 'Constraints', 'Description'],
['ClientID', 'AutoNumber', 'PRIMARY KEY', 'Unique identifier'],
['Nom', 'Text(100)', 'NOT NULL', 'Client name'],
['Email', 'Text(100)', 'VALIDATED', 'Email with format check'],
['Telephone', 'Text(20)', 'NULL', 'Phone number'],
['Notes', 'Memo', 'NULL', 'Additional notes'],
['DateCreation', 'DateTime', 'DEFAULT Now()', 'Creation timestamp'],
]
clt = Table(cl, colWidths=[1.3*inch, 1.3*inch, 1.5*inch, 2.4*inch])
clt.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), PRIMARY),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 9),
('FONTSIZE', (0,1), (-1,-1), 8),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('LEFTPADDING', (0,0), (-1,-1), 6),
('RIGHTPADDING', (0,0), (-1,-1), 6),
('TOPPADDING', (0,0), (-1,0), 8),
('BOTTOMPADDING', (0,0), (-1,0), 8),
('TOPPADDING', (0,1), (-1,-1), 5),
('BOTTOMPADDING', (0,1), (-1,-1), 5),
]))
story.append(clt)
story.append(Spacer(1, 0.2*inch))
story.append(Paragraph("3.3 Table: tbl_Projets", s['SubHead']))
pr = [
['Field', 'Type', 'Constraints', 'Description'],
['ProjetID', 'AutoNumber', 'PRIMARY KEY', 'Unique identifier'],
['ClientID', 'Long', 'FOREIGN KEY', 'Ref to tbl_Clients'],
['Nom', 'Text(100)', 'NOT NULL', 'Project name'],
['Description', 'Memo', 'NULL', 'Project details'],
['TauxHoraire', 'Currency', 'DEFAULT 0', 'Hourly rate (EUR)'],
['Actif', 'Yes/No', 'DEFAULT True', 'Active/archived'],
['DateCreation', 'DateTime', 'DEFAULT Now()', 'Creation timestamp'],
]
prt = Table(pr, colWidths=[1.3*inch, 1.3*inch, 1.5*inch, 2.4*inch])
prt.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), PRIMARY),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 9),
('FONTSIZE', (0,1), (-1,-1), 8),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('LEFTPADDING', (0,0), (-1,-1), 6),
('RIGHTPADDING', (0,0), (-1,-1), 6),
('TOPPADDING', (0,0), (-1,0), 8),
('BOTTOMPADDING', (0,0), (-1,0), 8),
('TOPPADDING', (0,1), (-1,-1), 5),
('BOTTOMPADDING', (0,1), (-1,-1), 5),
]))
story.append(prt)
story.append(Spacer(1, 0.2*inch))
story.append(Paragraph("3.4 Table: tbl_Temps", s['SubHead']))
tm = [
['Field', 'Type', 'Constraints', 'Description'],
['TempsID', 'AutoNumber', 'PRIMARY KEY', 'Unique identifier'],
['ProjetID', 'Long', 'FOREIGN KEY', 'Ref to tbl_Projets'],
['Date', 'DateTime', 'NOT NULL', 'Entry date (no future)'],
['Duree', 'Double', 'NOT NULL, > 0', 'Hours (decimal)'],
['Description', 'Memo', 'NULL', 'Work description'],
['DateCreation', 'DateTime', 'DEFAULT Now()', 'Creation timestamp'],
]
tmt = Table(tm, colWidths=[1.3*inch, 1.3*inch, 1.5*inch, 2.4*inch])
tmt.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), PRIMARY),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 9),
('FONTSIZE', (0,1), (-1,-1), 8),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('LEFTPADDING', (0,0), (-1,-1), 6),
('RIGHTPADDING', (0,0), (-1,-1), 6),
('TOPPADDING', (0,0), (-1,0), 8),
('BOTTOMPADDING', (0,0), (-1,0), 8),
('TOPPADDING', (0,1), (-1,-1), 5),
('BOTTOMPADDING', (0,1), (-1,-1), 5),
]))
story.append(tmt)
story.append(PageBreak())
# ========== SECTION 4 ==========
print(" - Section 4: VBA Architecture")
story.append(Paragraph("4. VBA Module Architecture", s['SHead']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph(
"Modular VBA architecture with 7 core modules totaling 915 lines of professional, commented code. Clear separation of concerns following best practices.", s['Body']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph("4.1 Module Overview", s['SubHead']))
mod = [
['Module', 'Purpose', 'LOC', 'Functions'],
['mod_Config', 'App configuration & constants', '80', ''],
['mod_Navigation', 'Form navigation & UI flow', '120', '7'],
['mod_DataAccess', 'CRUD operations & DB layer', '200', '15+'],
['mod_Calculs', 'Business logic & calculations', '150', '8'],
['mod_Export', 'Report generation & export', '120', '5'],
['mod_Utils', 'Helper functions & validation', '100', '8'],
['mod_FormBuilder', 'Automated form creation', '145', '6'],
]
modt = Table(mod, colWidths=[1.5*inch, 2.5*inch, 0.7*inch, 1*inch])
modt.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), PRIMARY),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 9),
('FONTSIZE', (0,1), (-1,-1), 9),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('ALIGN', (2,0), (3,-1), 'CENTER'),
('LEFTPADDING', (0,0), (-1,-1), 8),
('RIGHTPADDING', (0,0), (-1,-1), 8),
('TOPPADDING', (0,0), (-1,0), 10),
('BOTTOMPADDING', (0,0), (-1,0), 10),
('TOPPADDING', (0,1), (-1,-1), 6),
('BOTTOMPADDING', (0,1), (-1,-1), 6),
]))
story.append(modt)
story.append(Spacer(1, 0.2*inch))
story.append(Paragraph("4.2 Code Quality Metrics", s['SubHead']))
for item in [
"Total VBA Lines: <b>915</b>",
"Average Module Size: <b>~130 lines</b>",
"Total Functions: <b>45+</b>",
"Comment Ratio: <b>25%</b>",
"Error Handling: <b>100%</b> (all public functions)",
"Coding Standard: <b>Option Explicit</b>, meaningful names, consistent indentation"
]:
story.append(Paragraph(f"{item}", s['Bull']))
story.append(PageBreak())
# ========== SECTION 5 ==========
print(" - Section 5: Functional Specifications")
story.append(Paragraph("5. Functional Specifications", s['SHead']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph("5.1 Core Features", s['SubHead']))
feat = [
['Feature', 'Description', 'Status'],
['Client Management', 'Full CRUD for clients with contacts', '✓ Complete'],
['Project Management', 'Projects linked to clients with rates', '✓ Complete'],
['Time Entry', 'Quick entry with validation', '✓ Complete'],
['Automatic Calculations', 'Revenue by project/client', '✓ Complete'],
['Report Generation', 'Exportable PDF/Excel reports', '✓ Complete'],
['Data Validation', 'Email, phone, date validation', '✓ Complete'],
]
ft = Table(feat, colWidths=[2*inch, 3*inch, 1.5*inch])
ft.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), ACCENT),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 10),
('FONTSIZE', (0,1), (-1,-1), 9),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('LEFTPADDING', (0,0), (-1,-1), 8),
('RIGHTPADDING', (0,0), (-1,-1), 8),
('TOPPADDING', (0,0), (-1,0), 10),
('BOTTOMPADDING', (0,0), (-1,0), 10),
('TOPPADDING', (0,1), (-1,-1), 6),
('BOTTOMPADDING', (0,1), (-1,-1), 6),
('TEXTCOLOR', (2,1), (2,-1), SUCCESS),
('FONTNAME', (2,1), (2,-1), 'Helvetica-Bold'),
]))
story.append(ft)
story.append(Spacer(1, 0.2*inch))
story.append(Paragraph("5.2 User Interface", s['SubHead']))
ui = [
['Form', 'Purpose'],
['frm_Accueil', 'Main dashboard with navigation & statistics'],
['frm_Clients', 'Client list with add/edit/delete'],
['frm_Projets', 'Project management with client filter'],
['frm_SaisieTemps', 'Quick time entry (<30 sec target)'],
['frm_Historique', 'Time history with filters & export'],
]
uit = Table(ui, colWidths=[2*inch, 4.5*inch])
uit.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), PRIMARY),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('LEFTPADDING', (0,0), (-1,-1), 8),
('RIGHTPADDING', (0,0), (-1,-1), 8),
('TOPPADDING', (0,0), (-1,0), 10),
('BOTTOMPADDING', (0,0), (-1,0), 10),
('TOPPADDING', (0,1), (-1,-1), 8),
('BOTTOMPADDING', (0,1), (-1,-1), 8),
]))
story.append(uit)
story.append(PageBreak())
# ========== SECTION 6 ==========
print(" - Section 6: MCP VBA Automation")
story.append(Paragraph("6. MCP VBA Server Automation", s['SHead']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph(
"""This project showcases advanced automation using the VBA MCP Server (Model Context Protocol),
enabling AI-assisted development of Access applications. This cutting-edge approach demonstrates
the future of database application development.""", s['Body']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph("6.1 Development Efficiency", s['SubHead']))
dev = [
['Phase', 'Estimated', 'Actual', 'Method'],
['Database Design', '1h', '0.5h', 'MCP Automated'],
['Test Data', '30min', '15min', 'MCP Automated'],
['VBA Modules', '3h', '1h', 'MCP Automated'],
['SQL Queries', '30min', '20min', 'MCP Automated'],
['Forms', '2h', '1h', 'Script + Manual'],
['Testing & Docs', '2h', '2h', 'Manual'],
['TOTAL', '9h', '~5h', '45% Time Saved'],
]
devt = Table(dev, colWidths=[1.8*inch, 1.2*inch, 1.2*inch, 2.3*inch])
devt.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), PRIMARY),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 10),
('FONTSIZE', (0,1), (-1,-1), 9),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-2), [colors.white, LIGHT_GREY]),
('BACKGROUND', (0,-1), (-1,-1), SUCCESS),
('TEXTCOLOR', (0,-1), (-1,-1), colors.white),
('FONTNAME', (0,-1), (-1,-1), 'Helvetica-Bold'),
('FONTSIZE', (0,-1), (-1,-1), 11),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('LEFTPADDING', (0,0), (-1,-1), 8),
('RIGHTPADDING', (0,0), (-1,-1), 8),
('TOPPADDING', (0,0), (-1,-1), 8),
('BOTTOMPADDING', (0,0), (-1,-1), 8),
]))
story.append(devt)
story.append(Spacer(1, 0.2*inch))
story.append(Paragraph("6.2 MCP Tools Used", s['SubHead']))
for item in [
"<b>run_access_query</b> - DDL/DML SQL execution",
"<b>inject_vba</b> - Module code injection",
"<b>validate_vba_code</b> - Pre-injection syntax check",
"<b>get/set_worksheet_data</b> - Bulk data operations",
"<b>list_access_tables</b> - Schema verification",
"<b>compile_vba</b> - Compilation error detection",
"<b>backup_vba</b> - Safety backups before changes"
]:
story.append(Paragraph(f"{item}", s['Bull']))
story.append(PageBreak())
# ========== SECTION 7 ==========
print(" - Section 7: Use Cases")
story.append(Paragraph("7. Use Cases & Applications", s['SHead']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph("7.1 Freelance Consultant", s['SubHead']))
story.append(Paragraph(
"""<b>Scenario:</b> Independent consultant managing 5 clients with 8 ongoing projects.""",
s['Body']))
for item in [
"Log time daily (2 min/day)",
"Review weekly hours by project",
"Generate monthly client reports",
"Export to Excel for accounting"
]:
story.append(Paragraph(f"{item}", s['Bull']))
story.append(Spacer(1, 0.1*inch))
story.append(Paragraph("7.2 Small Design Agency", s['SubHead']))
story.append(Paragraph(
"""<b>Scenario:</b> 3-person team tracking time across 10 client projects.""",
s['Body']))
for item in [
"Team members log time per project",
"Manager reviews hours weekly",
"Generate client reports at milestones",
"Calculate project profitability"
]:
story.append(Paragraph(f"{item}", s['Bull']))
story.append(Spacer(1, 0.1*inch))
story.append(Paragraph("7.3 IT Contractor", s['SubHead']))
story.append(Paragraph(
"""<b>Scenario:</b> IT professional with retainer clients and hourly projects.""",
s['Body']))
for item in [
"Different rates per project/client",
"Track support vs project hours",
"Monitor retainer budgets",
"Detailed invoices with descriptions"
]:
story.append(Paragraph(f"{item}", s['Bull']))
story.append(PageBreak())
# ========== SECTION 8 ==========
print(" - Section 8: Installation")
story.append(Paragraph("8. Installation & Deployment", s['SHead']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph("8.1 Prerequisites", s['SubHead']))
for item in [
"Windows 10/11",
"Microsoft Access 2016+ or Office 365 with Access",
"Macro security: Enable VBA macros"
]:
story.append(Paragraph(f"{item}", s['Bull']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph("8.2 Quick Start", s['SubHead']))
inst = """
1. Clone/download project
2. Open db/TimeTrackPro.accdb
3. Enable macros when prompted
4. Import forms (first time):
- Alt+F11 Import scripts/modules/mod_FormBuilder.bas
- Ctrl+G BuildAllForms Enter
5. Start using application
"""
story.append(Paragraph(inst, s['CodeBlock']))
story.append(Spacer(1, 0.2*inch))
story.append(Paragraph("8.3 Deployment Options", s['SubHead']))
dep = [
['Option', 'Description', 'Best For'],
['Single-User', 'Copy .accdb to user machine', 'Personal use'],
['Split Database', 'Frontend + backend on network', 'Team (< 10 users)'],
['SQL Server', 'Migrate to SQL Server backend', 'Enterprise'],
]
dept = Table(dep, colWidths=[1.5*inch, 3*inch, 2*inch])
dept.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), ACCENT),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('LEFTPADDING', (0,0), (-1,-1), 8),
('RIGHTPADDING', (0,0), (-1,-1), 8),
('TOPPADDING', (0,0), (-1,0), 10),
('BOTTOMPADDING', (0,0), (-1,0), 10),
('TOPPADDING', (0,1), (-1,-1), 8),
('BOTTOMPADDING', (0,1), (-1,-1), 8),
]))
story.append(dept)
story.append(PageBreak())
# ========== SECTION 9 ==========
print(" - Section 9: Professional Services")
story.append(Paragraph("9. Professional Services Available", s['SHead']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph(
"This project demonstrates expertise in the following areas:", s['Body']))
story.append(Spacer(1, 0.15*inch))
serv = [
['Service', 'Description'],
['Microsoft Access Development', 'Forms, reports, VBA automation, SQL optimization'],
['Database Design', 'Normalization, indexing, referential integrity, performance'],
['Business Applications', 'Requirements, UX design, testing, deployment'],
['Process Automation', 'VBA macros, MCP integration, workflow optimization'],
['Legacy Modernization', 'Access to SQL Server/web migration'],
['AI-Assisted Development', 'MCP Server integration, cutting-edge automation'],
]
servt = Table(serv, colWidths=[2.3*inch, 4.2*inch])
servt.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), PRIMARY),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTNAME', (0,1), (0,-1), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 11),
('FONTSIZE', (0,1), (-1,-1), 10),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'TOP'),
('LEFTPADDING', (0,0), (-1,-1), 10),
('RIGHTPADDING', (0,0), (-1,-1), 10),
('TOPPADDING', (0,0), (-1,0), 10),
('BOTTOMPADDING', (0,0), (-1,0), 10),
('TOPPADDING', (0,1), (-1,-1), 8),
('BOTTOMPADDING', (0,1), (-1,-1), 8),
]))
story.append(servt)
story.append(Spacer(1, 0.3*inch))
# Contact box
contact_data = [[
Paragraph("<b>Contact Information</b>", ParagraphStyle('CB', parent=s['Body'],
fontSize=14, alignment=TA_CENTER, textColor=colors.white,
fontName='Helvetica-Bold')),
Paragraph('Alexis Trouvé<br/>alexistrouve.pro@gmail.com<br/><link href="https://github.com/AlexisTrouve?tab=repositories" color="white">github.com/AlexisTrouve</link><br/><i>Response time: Within 24 hours</i>',
ParagraphStyle('CC', parent=s['Body'], fontSize=11,
alignment=TA_CENTER, textColor=colors.white))
]]
ct = Table(contact_data, colWidths=[6.5*inch])
ct.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,-1), PRIMARY),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('LEFTPADDING', (0,0), (-1,-1), 20),
('RIGHTPADDING', (0,0), (-1,-1), 20),
('TOPPADDING', (0,0), (-1,-1), 15),
('BOTTOMPADDING', (0,0), (-1,-1), 15),
]))
story.append(ct)
story.append(PageBreak())
# ========== SECTION 10 ==========
print(" - Section 10: Appendices")
story.append(Paragraph("10. Appendices & Resources", s['SHead']))
story.append(Spacer(1, 0.15*inch))
story.append(Paragraph("10.1 Documentation Files", s['SubHead']))
docs = [
['File', 'Purpose'],
['README.md', 'Project overview and quick start'],
['TECHNICAL_REFERENCE.md', 'Complete technical reference'],
['DATABASE.md', 'Detailed database schema'],
['VBA_MODULES.md', 'VBA code documentation'],
['PLAN.md', 'Project development plan'],
['CHANGELOG.md', 'Version history'],
['docs/MCP_VBA_GUIDE.md', 'MCP VBA usage guide'],
]
docst = Table(docs, colWidths=[2.5*inch, 4*inch])
docst.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), ACCENT),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTNAME', (0,1), (0,-1), 'Courier'),
('FONTSIZE', (0,0), (-1,0), 10),
('FONTSIZE', (0,1), (-1,-1), 9),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('LEFTPADDING', (0,0), (-1,-1), 8),
('RIGHTPADDING', (0,0), (-1,-1), 8),
('TOPPADDING', (0,0), (-1,0), 10),
('BOTTOMPADDING', (0,0), (-1,0), 10),
('TOPPADDING', (0,1), (-1,-1), 6),
('BOTTOMPADDING', (0,1), (-1,-1), 6),
]))
story.append(docst)
story.append(Spacer(1, 0.2*inch))
story.append(Paragraph("10.2 License & Usage", s['SubHead']))
for item in [
"<b>License:</b> MIT License",
"<b>Commercial Use:</b> Permitted",
"<b>Modification:</b> Permitted",
"<b>Distribution:</b> Permitted",
"<b>Private Use:</b> Permitted"
]:
story.append(Paragraph(f"{item}", s['Bull']))
story.append(Spacer(1, 0.2*inch))
story.append(Paragraph("10.3 Version Information", s['SubHead']))
ver = [
['Item', 'Details'],
['Document Version', '1.0'],
['Application Version', '1.0'],
['Last Updated', 'January 13, 2025'],
['Status', 'Production Ready'],
]
vert = Table(ver, colWidths=[2*inch, 4.5*inch])
vert.setStyle(TableStyle([
('BACKGROUND', (0,0), (-1,0), PRIMARY),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 10),
('GRID', (0,0), (-1,-1), 0.5, GREY),
('ROWBACKGROUNDS', (0,1), (-1,-1), [colors.white, LIGHT_GREY]),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('LEFTPADDING', (0,0), (-1,-1), 10),
('RIGHTPADDING', (0,0), (-1,-1), 10),
('TOPPADDING', (0,0), (-1,-1), 8),
('BOTTOMPADDING', (0,0), (-1,-1), 8),
]))
story.append(vert)
story.append(Spacer(1, 0.5*inch))
# Final note
final = ParagraphStyle('Final', parent=s['Body'], fontSize=10,
alignment=TA_CENTER, textColor=GREY,
fontName='Helvetica-Oblique')
story.append(HRFlowable(width="50%", thickness=1, color=GREY,
spaceAfter=15, spaceBefore=15, hAlign='CENTER'))
story.append(Paragraph(
"This document serves as the authoritative technical and functional reference for TimeTrack Pro.",
final))
story.append(Paragraph(
"For development assistance or custom modifications, contact the author.",
final))
# Build PDF
print("\nBuilding PDF with page numbers...")
doc.build(story, canvasmaker=NumberedCanvas)
print(f"\n{'='*60}")
print(f"SUCCESS - Professional PDF generated!")
print(f"{'='*60}")
print(f"File: {OUTPUT}")
import os
size = os.path.getsize(OUTPUT) / 1024
print(f"Size: {size:.1f} KB")
print(f"Sections: 10 complete sections")
print(f"Tables: 15+ professional tables")
print(f"Pages: ~15-20 pages with headers/footers")
print(f"{'='*60}\n")
if __name__ == '__main__':
build_pdf()

View File

@ -0,0 +1,703 @@
#!/usr/bin/env python3
"""
Professional PDF Generator for TimeTrack Pro Technical Reference
Creates a comprehensive, beautifully formatted technical document
"""
from reportlab.lib import colors
from reportlab.lib.pagesizes import letter, A4
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from reportlab.lib.enums import TA_LEFT, TA_CENTER, TA_RIGHT, TA_JUSTIFY
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, PageBreak, Table, TableStyle,
Image, KeepTogether, ListFlowable, ListItem, HRFlowable
)
from reportlab.pdfgen import canvas
from datetime import datetime
# Professional color scheme
PRIMARY_COLOR = colors.HexColor('#2C3E50') # Dark blue-grey
ACCENT_COLOR = colors.HexColor('#2980B9') # Professional blue
LIGHT_ACCENT = colors.HexColor('#3498DB') # Light blue
SUCCESS_COLOR = colors.HexColor('#27AE60') # Green
GREY_COLOR = colors.HexColor('#7F8C8D') # Grey
LIGHT_GREY = colors.HexColor('#ECF0F1') # Light grey
OUTPUT_FILE = r"C:\Users\alexi\Documents\projects\timetrack-pro\TimeTrack_Pro_Professional_Documentation.pdf"
class NumberedCanvas(canvas.Canvas):
"""Custom canvas for page numbers and headers/footers"""
def __init__(self, *args, **kwargs):
canvas.Canvas.__init__(self, *args, **kwargs)
self._saved_page_states = []
def showPage(self):
self._saved_page_states.append(dict(self.__dict__))
self._startPage()
def save(self):
num_pages = len(self._saved_page_states)
for state in self._saved_page_states:
self.__dict__.update(state)
self.draw_page_decorations(num_pages)
canvas.Canvas.showPage(self)
canvas.Canvas.save(self)
def draw_page_decorations(self, page_count):
self.saveState()
self.setFont('Helvetica', 9)
# Page number in footer
page_num = f"Page {self._pageNumber} of {page_count}"
self.setFillColor(GREY_COLOR)
self.drawCentredString(letter[0] / 2, 0.5 * inch, page_num)
# Document title in header (skip first page)
if self._pageNumber > 1:
self.setFillColor(GREY_COLOR)
self.drawString(0.75 * inch, letter[1] - 0.5 * inch,
"TimeTrack Pro - Technical Reference")
self.drawRightString(letter[0] - 0.75 * inch, letter[1] - 0.5 * inch,
"Alexis Trouvé | 2025")
self.restoreState()
def create_styles():
"""Create custom paragraph styles"""
styles = getSampleStyleSheet()
# Cover title
styles.add(ParagraphStyle(
name='CoverTitle',
parent=styles['Heading1'],
fontSize=48,
textColor=PRIMARY_COLOR,
spaceAfter=20,
alignment=TA_CENTER,
fontName='Helvetica-Bold'
))
# Cover subtitle
styles.add(ParagraphStyle(
name='CoverSubtitle',
parent=styles['Normal'],
fontSize=24,
textColor=ACCENT_COLOR,
spaceAfter=30,
alignment=TA_CENTER,
fontName='Helvetica'
))
# Section header
styles.add(ParagraphStyle(
name='SectionHeader',
parent=styles['Heading1'],
fontSize=20,
textColor=colors.white,
backColor=PRIMARY_COLOR,
spaceAfter=16,
spaceBefore=12,
leftIndent=10,
fontName='Helvetica-Bold',
leading=28
))
# Subsection header
styles.add(ParagraphStyle(
name='SubsectionHeader',
parent=styles['Heading2'],
fontSize=14,
textColor=ACCENT_COLOR,
spaceAfter=10,
spaceBefore=12,
fontName='Helvetica-Bold'
))
# Body text
styles.add(ParagraphStyle(
name='BodyText',
parent=styles['Normal'],
fontSize=11,
textColor=PRIMARY_COLOR,
alignment=TA_JUSTIFY,
spaceAfter=8,
leading=14
))
# Bullet points
styles.add(ParagraphStyle(
name='Bullet',
parent=styles['Normal'],
fontSize=11,
textColor=PRIMARY_COLOR,
leftIndent=30,
spaceAfter=6,
leading=14
))
# Highlight box
styles.add(ParagraphStyle(
name='HighlightBox',
parent=styles['Normal'],
fontSize=12,
textColor=colors.white,
backColor=ACCENT_COLOR,
alignment=TA_CENTER,
spaceAfter=12,
spaceBefore=12,
leftIndent=20,
rightIndent=20,
borderPadding=10,
fontName='Helvetica-Bold'
))
# Code/Technical
styles.add(ParagraphStyle(
name='Code',
parent=styles['Normal'],
fontSize=9,
textColor=PRIMARY_COLOR,
fontName='Courier',
leftIndent=20,
backColor=LIGHT_GREY,
spaceAfter=8
))
return styles
def create_cover_page(story, styles):
"""Create professional cover page"""
# Title
story.append(Spacer(1, 1.5 * inch))
story.append(Paragraph("TimeTrack Pro", styles['CoverTitle']))
story.append(Spacer(1, 0.3 * inch))
# Subtitle
story.append(Paragraph("Technical & Functional Reference", styles['CoverSubtitle']))
story.append(Spacer(1, 0.2 * inch))
# Horizontal line
story.append(HRFlowable(width="70%", thickness=2, color=ACCENT_COLOR,
spaceAfter=30, spaceBefore=10, hAlign='CENTER'))
# Description
desc_style = ParagraphStyle(
'CoverDesc',
parent=styles['BodyText'],
fontSize=13,
alignment=TA_CENTER,
textColor=PRIMARY_COLOR,
fontName='Helvetica-Oblique'
)
story.append(Paragraph("Professional Time Tracking Application", desc_style))
story.append(Paragraph("Built with Microsoft Access & VBA", desc_style))
story.append(Paragraph("Automated Development via MCP VBA Server", desc_style))
story.append(Spacer(1, 0.5 * inch))
# Key highlights box
highlights_data = [
['Project Highlights', ''],
['Total VBA Code', '915 Lines'],
['Modular Components', '7 Modules'],
['Database Tables', '3 Normalized Tables'],
['Public Functions', '45+ Functions'],
['Development Time Saved', '45% via Automation'],
['Code Quality', '25% Comment Ratio'],
]
highlights_table = Table(highlights_data, colWidths=[3*inch, 2*inch])
highlights_table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, 0), PRIMARY_COLOR),
('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
('ALIGN', (0, 0), (-1, 0), 'CENTER'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 14),
('BOTTOMPADDING', (0, 0), (-1, 0), 12),
('TOPPADDING', (0, 0), (-1, 0), 12),
('BACKGROUND', (0, 1), (0, -1), LIGHT_GREY),
('BACKGROUND', (1, 1), (1, -1), colors.white),
('TEXTCOLOR', (0, 1), (-1, -1), PRIMARY_COLOR),
('FONTNAME', (0, 1), (0, -1), 'Helvetica-Bold'),
('FONTNAME', (1, 1), (1, -1), 'Helvetica'),
('FONTSIZE', (0, 1), (-1, -1), 11),
('ALIGN', (0, 0), (-1, -1), 'LEFT'),
('ALIGN', (1, 1), (1, -1), 'RIGHT'),
('GRID', (0, 0), (-1, -1), 0.5, GREY_COLOR),
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('LEFTPADDING', (0, 0), (-1, -1), 10),
('RIGHTPADDING', (0, 0), (-1, -1), 10),
('TOPPADDING', (0, 1), (-1, -1), 8),
('BOTTOMPADDING', (0, 1), (-1, -1), 8),
]))
story.append(highlights_table)
story.append(Spacer(1, 1 * inch))
# Author info
author_style = ParagraphStyle(
'Author',
parent=styles['BodyText'],
fontSize=13,
alignment=TA_CENTER,
textColor=PRIMARY_COLOR,
fontName='Helvetica-Bold'
)
contact_style = ParagraphStyle(
'Contact',
parent=styles['BodyText'],
fontSize=11,
alignment=TA_CENTER,
textColor=ACCENT_COLOR
)
story.append(Paragraph("Alexis Trouvé", author_style))
story.append(Spacer(1, 0.1 * inch))
story.append(Paragraph("alexistrouve.pro@gmail.com", contact_style))
story.append(Spacer(1, 0.3 * inch))
version_style = ParagraphStyle(
'Version',
parent=styles['BodyText'],
fontSize=10,
alignment=TA_CENTER,
textColor=GREY_COLOR
)
story.append(Paragraph("Version 1.0 | January 2025", version_style))
story.append(PageBreak())
def create_section_1_executive_summary(story, styles):
"""Section 1: Executive Summary"""
story.append(Paragraph("1. Executive Summary", styles['SectionHeader']))
story.append(Spacer(1, 0.15 * inch))
story.append(Paragraph(
"""TimeTrack Pro is a professional time tracking application built on Microsoft Access,
showcasing advanced database design, VBA automation, and modern development practices.
This project demonstrates the capability to deliver production-ready business applications
through automated development workflows using the VBA MCP Server.""",
styles['BodyText']
))
story.append(Spacer(1, 0.1 * inch))
story.append(Paragraph(
"""<b><font color="#2980B9">Key Achievement:</font></b> Complete application development
(database structure, business logic, queries, and VBA modules) automated via MCP
(Model Context Protocol) integration, demonstrating cutting-edge AI-assisted development
capabilities.""",
styles['BodyText']
))
story.append(Spacer(1, 0.2 * inch))
# Statistics table
story.append(Paragraph("1.1 Project Statistics", styles['SubsectionHeader']))
stats_data = [
['Metric', 'Value', 'Description'],
['Total VBA Lines', '915', 'Professional, commented code'],
['VBA Modules', '7', 'Modular architecture with separation of concerns'],
['Database Tables', '3', 'Normalized relational structure'],
['Public Functions', '45+', 'Reusable business logic components'],
['Development Time Saved', '45%', 'Via MCP VBA automation'],
['Comment Ratio', '25%', 'Well-documented codebase'],
['Error Handling', '100%', 'All public functions include error handling'],
]
stats_table = Table(stats_data, colWidths=[2*inch, 1.5*inch, 3*inch])
stats_table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, 0), PRIMARY_COLOR),
('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
('ALIGN', (0, 0), (-1, -1), 'LEFT'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 11),
('BOTTOMPADDING', (0, 0), (-1, 0), 10),
('TOPPADDING', (0, 0), (-1, 0), 10),
('BACKGROUND', (0, 1), (-1, -1), colors.white),
('TEXTCOLOR', (0, 1), (-1, -1), PRIMARY_COLOR),
('FONTNAME', (0, 1), (-1, -1), 'Helvetica'),
('FONTSIZE', (0, 1), (-1, -1), 10),
('GRID', (0, 0), (-1, -1), 0.5, GREY_COLOR),
('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, LIGHT_GREY]),
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('LEFTPADDING', (0, 0), (-1, -1), 8),
('RIGHTPADDING', (0, 0), (-1, -1), 8),
('TOPPADDING', (0, 1), (-1, -1), 6),
('BOTTOMPADDING', (0, 1), (-1, -1), 6),
]))
story.append(stats_table)
story.append(Spacer(1, 0.2 * inch))
# Current usage data
story.append(Paragraph("1.2 Current Application Data", styles['SubsectionHeader']))
usage_data = [
['Metric', 'Value'],
['Active Clients', '4'],
['Active Projects', '6'],
['Total Time Entries', '15+'],
['Total Hours Tracked', '58 hours'],
['Total Revenue Calculated', '€4,732.50'],
]
usage_table = Table(usage_data, colWidths=[3*inch, 2*inch])
usage_table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, 0), ACCENT_COLOR),
('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
('ALIGN', (0, 0), (0, -1), 'LEFT'),
('ALIGN', (1, 0), (1, -1), 'RIGHT'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 11),
('FONTNAME', (1, 1), (1, -1), 'Helvetica-Bold'),
('FONTSIZE', (1, 1), (1, -1), 12),
('TEXTCOLOR', (1, 1), (1, -1), SUCCESS_COLOR),
('BOTTOMPADDING', (0, 0), (-1, 0), 10),
('TOPPADDING', (0, 0), (-1, 0), 10),
('GRID', (0, 0), (-1, -1), 0.5, GREY_COLOR),
('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, LIGHT_GREY]),
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('LEFTPADDING', (0, 0), (-1, -1), 10),
('RIGHTPADDING', (0, 0), (-1, -1), 10),
('TOPPADDING', (0, 1), (-1, -1), 8),
('BOTTOMPADDING', (0, 1), (-1, -1), 8),
]))
story.append(usage_table)
story.append(PageBreak())
def create_section_2_project_overview(story, styles):
"""Section 2: Project Overview"""
story.append(Paragraph("2. Project Overview", styles['SectionHeader']))
story.append(Spacer(1, 0.15 * inch))
# Purpose
story.append(Paragraph("2.1 Purpose", styles['SubsectionHeader']))
story.append(Paragraph(
"""TimeTrack Pro is a time management tool designed for freelancers, consultants,
and small teams to:""",
styles['BodyText']
))
bullets = [
"Track billable hours across multiple clients and projects",
"Calculate revenue automatically based on hourly rates",
"Generate professional reports for invoicing and analysis",
"Maintain a complete audit trail of time entries"
]
for bullet in bullets:
story.append(Paragraph(f"{bullet}", styles['Bullet']))
story.append(Spacer(1, 0.15 * inch))
# Target Audience
story.append(Paragraph("2.2 Target Audience", styles['SubsectionHeader']))
audience_data = [
['Audience', 'Use Case'],
['Freelancers', 'Independent consultants tracking multiple client projects and generating invoices'],
['Small Teams', 'Agencies managing client work, resource allocation, and team productivity'],
['Consultants', 'Professional services requiring detailed time records and client reporting'],
]
audience_table = Table(audience_data, colWidths=[1.5*inch, 5*inch])
audience_table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, 0), ACCENT_COLOR),
('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
('ALIGN', (0, 0), (-1, -1), 'LEFT'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 11),
('BOTTOMPADDING', (0, 0), (-1, 0), 10),
('TOPPADDING', (0, 0), (-1, 0), 10),
('GRID', (0, 0), (-1, -1), 0.5, GREY_COLOR),
('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, LIGHT_GREY]),
('VALIGN', (0, 0), (-1, -1), 'TOP'),
('LEFTPADDING', (0, 0), (-1, -1), 8),
('RIGHTPADDING', (0, 0), (-1, -1), 8),
('TOPPADDING', (0, 1), (-1, -1), 8),
('BOTTOMPADDING', (0, 1), (-1, -1), 8),
]))
story.append(audience_table)
story.append(Spacer(1, 0.2 * inch))
# Differentiators
story.append(Paragraph("2.3 Key Differentiators", styles['SubsectionHeader']))
diff_bullets = [
"<b>Automated Development:</b> Built using VBA MCP Server v0.6.0+ for database automation",
"<b>Clean Architecture:</b> Modular VBA design with clear separation of concerns",
"<b>Production-Ready:</b> Complete with data validation, error handling, and user-friendly interfaces",
"<b>Extensible:</b> Well-documented codebase ready for customization and enhancement",
"<b>AI-Assisted:</b> Demonstrates cutting-edge development practices with MCP integration"
]
for bullet in diff_bullets:
story.append(Paragraph(f"{bullet}", styles['Bullet']))
story.append(Spacer(1, 0.2 * inch))
# Technology Stack
story.append(Paragraph("2.4 Technology Stack", styles['SubsectionHeader']))
tech_data = [
['Component', 'Technology', 'Version/Details'],
['Database Engine', 'Microsoft Access', '2016+ / Office 365'],
['Programming Language', 'VBA', 'Visual Basic for Applications 7.1'],
['Development Automation', 'VBA MCP Server', 'v0.6.0+ (Model Context Protocol)'],
['Export Formats', 'PDF, Excel', 'Native Access/VBA integration'],
['Version Control', 'Git', '2.x with source file exports'],
]
tech_table = Table(tech_data, colWidths=[2*inch, 2.2*inch, 2.3*inch])
tech_table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, 0), PRIMARY_COLOR),
('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
('ALIGN', (0, 0), (-1, -1), 'LEFT'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 10),
('FONTSIZE', (0, 1), (-1, -1), 9),
('BOTTOMPADDING', (0, 0), (-1, 0), 10),
('TOPPADDING', (0, 0), (-1, 0), 10),
('GRID', (0, 0), (-1, -1), 0.5, GREY_COLOR),
('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, LIGHT_GREY]),
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('LEFTPADDING', (0, 0), (-1, -1), 8),
('RIGHTPADDING', (0, 0), (-1, -1), 8),
('TOPPADDING', (0, 1), (-1, -1), 6),
('BOTTOMPADDING', (0, 1), (-1, -1), 6),
]))
story.append(tech_table)
story.append(PageBreak())
def create_section_3_database(story, styles):
"""Section 3: Database Architecture"""
story.append(Paragraph("3. Database Architecture", styles['SectionHeader']))
story.append(Spacer(1, 0.15 * inch))
story.append(Paragraph(
"""The application uses a normalized relational database structure following third normal
form (3NF) principles. The schema consists of three core tables with enforced referential
integrity and optimized indexes for query performance.""",
styles['BodyText']
))
story.append(Spacer(1, 0.15 * inch))
# ERD description
story.append(Paragraph("3.1 Entity Relationship Diagram", styles['SubsectionHeader']))
erd_code = """
tbl_Clients (1) (N) tbl_Projets
tbl_Projets (1) (N) tbl_Temps
Relationships:
One Client can have many Projects (1:N)
One Project can have many Time Entries (1:N)
Referential integrity enforced with CASCADE options
"""
story.append(Paragraph(erd_code, styles['Code']))
story.append(Spacer(1, 0.2 * inch))
# Table: tbl_Clients
story.append(Paragraph("3.2 Table: tbl_Clients", styles['SubsectionHeader']))
story.append(Paragraph("Stores client information and contact details.", styles['BodyText']))
story.append(Spacer(1, 0.1 * inch))
clients_data = [
['Field', 'Type', 'Size', 'Constraints', 'Description'],
['ClientID', 'AutoNumber', 'Long', 'PRIMARY KEY', 'Unique identifier'],
['Nom', 'Text', '100', 'NOT NULL', 'Client name'],
['Email', 'Text', '100', 'NULL, VALIDATED', 'Email address with format validation'],
['Telephone', 'Text', '20', 'NULL', 'Phone number'],
['Notes', 'Memo', '', 'NULL', 'Additional notes and comments'],
['DateCreation', 'DateTime', '', 'NOT NULL, DEFAULT Now()', 'Record creation timestamp'],
]
clients_table = Table(clients_data, colWidths=[1.2*inch, 1*inch, 0.7*inch, 1.4*inch, 2.2*inch])
clients_table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, 0), PRIMARY_COLOR),
('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
('ALIGN', (0, 0), (-1, -1), 'LEFT'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 9),
('FONTSIZE', (0, 1), (-1, -1), 8),
('BOTTOMPADDING', (0, 0), (-1, 0), 8),
('TOPPADDING', (0, 0), (-1, 0), 8),
('GRID', (0, 0), (-1, -1), 0.5, GREY_COLOR),
('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, LIGHT_GREY]),
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('LEFTPADDING', (0, 0), (-1, -1), 6),
('RIGHTPADDING', (0, 0), (-1, -1), 6),
('TOPPADDING', (0, 1), (-1, -1), 5),
('BOTTOMPADDING', (0, 1), (-1, -1), 5),
]))
story.append(clients_table)
story.append(Spacer(1, 0.15 * inch))
# Indexes
index_style = ParagraphStyle('IndexNote', parent=styles['BodyText'], fontSize=9,
textColor=GREY_COLOR, fontName='Helvetica-Oblique')
story.append(Paragraph("<b>Indexes:</b> PRIMARY KEY on ClientID, Search Index on Nom", index_style))
story.append(Spacer(1, 0.2 * inch))
# Table: tbl_Projets
story.append(Paragraph("3.3 Table: tbl_Projets", styles['SubsectionHeader']))
story.append(Paragraph("Stores project information linked to clients.", styles['BodyText']))
story.append(Spacer(1, 0.1 * inch))
projets_data = [
['Field', 'Type', 'Size', 'Constraints', 'Description'],
['ProjetID', 'AutoNumber', 'Long', 'PRIMARY KEY', 'Unique identifier'],
['ClientID', 'Long', '', 'FOREIGN KEY', 'Reference to tbl_Clients.ClientID'],
['Nom', 'Text', '100', 'NOT NULL', 'Project name'],
['Description', 'Memo', '', 'NULL', 'Project description and notes'],
['TauxHoraire', 'Currency', '', 'DEFAULT 0, >= 0', 'Hourly rate in EUR'],
['Actif', 'Yes/No', '', 'NOT NULL, DEFAULT True', 'Active/archived status'],
['DateCreation', 'DateTime', '', 'NOT NULL, DEFAULT Now()', 'Record creation timestamp'],
]
projets_table = Table(projets_data, colWidths=[1.2*inch, 1*inch, 0.7*inch, 1.4*inch, 2.2*inch])
projets_table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, 0), PRIMARY_COLOR),
('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
('ALIGN', (0, 0), (-1, -1), 'LEFT'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 9),
('FONTSIZE', (0, 1), (-1, -1), 8),
('BOTTOMPADDING', (0, 0), (-1, 0), 8),
('TOPPADDING', (0, 0), (-1, 0), 8),
('GRID', (0, 0), (-1, -1), 0.5, GREY_COLOR),
('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, LIGHT_GREY]),
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('LEFTPADDING', (0, 0), (-1, -1), 6),
('RIGHTPADDING', (0, 0), (-1, -1), 6),
('TOPPADDING', (0, 1), (-1, -1), 5),
('BOTTOMPADDING', (0, 1), (-1, -1), 5),
]))
story.append(projets_table)
story.append(Spacer(1, 0.15 * inch))
story.append(Paragraph("<b>Indexes:</b> PRIMARY KEY on ProjetID, FOREIGN KEY on ClientID (with referential integrity), Performance Index on Actif", index_style))
story.append(Spacer(1, 0.2 * inch))
# Table: tbl_Temps
story.append(Paragraph("3.4 Table: tbl_Temps", styles['SubsectionHeader']))
story.append(Paragraph("Stores time entry records.", styles['BodyText']))
story.append(Spacer(1, 0.1 * inch))
temps_data = [
['Field', 'Type', 'Size', 'Constraints', 'Description'],
['TempsID', 'AutoNumber', 'Long', 'PRIMARY KEY', 'Unique identifier'],
['ProjetID', 'Long', '', 'FOREIGN KEY', 'Reference to tbl_Projets.ProjetID'],
['Date', 'DateTime', '', 'NOT NULL', 'Entry date (no future dates allowed)'],
['Duree', 'Double', '', 'NOT NULL, > 0', 'Duration in hours (decimal)'],
['Description', 'Memo', '', 'NULL', 'Work description'],
['DateCreation', 'DateTime', '', 'NOT NULL, DEFAULT Now()', 'Record creation timestamp'],
]
temps_table = Table(temps_data, colWidths=[1.2*inch, 1*inch, 0.7*inch, 1.4*inch, 2.2*inch])
temps_table.setStyle(TableStyle([
('BACKGROUND', (0, 0), (-1, 0), PRIMARY_COLOR),
('TEXTCOLOR', (0, 0), (-1, 0), colors.white),
('ALIGN', (0, 0), (-1, -1), 'LEFT'),
('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
('FONTSIZE', (0, 0), (-1, 0), 9),
('FONTSIZE', (0, 1), (-1, -1), 8),
('BOTTOMPADDING', (0, 0), (-1, 0), 8),
('TOPPADDING', (0, 0), (-1, 0), 8),
('GRID', (0, 0), (-1, -1), 0.5, GREY_COLOR),
('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, LIGHT_GREY]),
('VALIGN', (0, 0), (-1, -1), 'MIDDLE'),
('LEFTPADDING', (0, 0), (-1, -1), 6),
('RIGHTPADDING', (0, 0), (-1, -1), 6),
('TOPPADDING', (0, 1), (-1, -1), 5),
('BOTTOMPADDING', (0, 1), (-1, -1), 5),
]))
story.append(temps_table)
story.append(Spacer(1, 0.15 * inch))
story.append(Paragraph("<b>Indexes:</b> PRIMARY KEY on TempsID, FOREIGN KEY on ProjetID (with referential integrity), Performance Index on Date (for date range queries)", index_style))
story.append(Spacer(1, 0.2 * inch))
# Data Integrity
story.append(Paragraph("3.5 Data Integrity Rules", styles['SubsectionHeader']))
integrity_bullets = [
"<b>Referential Integrity:</b> Foreign key constraints enforced with configurable CASCADE options",
"<b>Email Validation:</b> Format validation on tbl_Clients.Email field",
"<b>Positive Values:</b> CHECK constraints for TauxHoraire and Duree (must be >= 0)",
"<b>Date Validation:</b> No future dates allowed beyond today's date",
"<b>Orphan Prevention:</b> All foreign key constraints prevent orphaned records",
"<b>Audit Trail:</b> All tables include DateCreation timestamps for tracking"
]
for bullet in integrity_bullets:
story.append(Paragraph(f"{bullet}", styles['Bullet']))
story.append(PageBreak())
# Continue in next part...
print("Creating professional PDF documentation...")
print("This script will generate a complete technical reference document.")
print("")
# Create PDF
doc = SimpleDocTemplate(
OUTPUT_FILE,
pagesize=letter,
rightMargin=0.75*inch,
leftMargin=0.75*inch,
topMargin=1*inch,
bottomMargin=0.75*inch,
title="TimeTrack Pro - Technical Reference",
author="Alexis Trouvé"
)
# Create custom styles
styles = create_styles()
# Story container
story = []
# Build document
print("Creating cover page...")
create_cover_page(story, styles)
print("Creating Section 1: Executive Summary...")
create_section_1_executive_summary(story, styles)
print("Creating Section 2: Project Overview...")
create_section_2_project_overview(story, styles)
print("Creating Section 3: Database Architecture...")
create_section_3_database(story, styles)
print("\nNote: This is Part 1. Continue with additional sections...")
print("Generating PDF (Part 1)...")
# Build PDF with custom canvas
doc.build(story, canvasmaker=NumberedCanvas)
print(f"\n✓ PDF generated successfully!")
print(f"Location: {OUTPUT_FILE}")
print(f"\nNote: This is a partial document. Run Part 2 script to add remaining sections.")

View File

@ -0,0 +1,186 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TimeTrack Pro - Accueil</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 40px 20px;
}
.form-section {
background: white;
border-radius: 20px;
padding: 35px;
margin-bottom: 30px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
animation: slideUp 0.6s ease-out;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.section-title {
color: #667eea;
font-size: 1.8em;
font-weight: bold;
margin-bottom: 25px;
padding-bottom: 15px;
border-bottom: 3px solid #667eea;
}
.section-title:before {
content: '📊 ';
font-size: 1.2em;
}
.form-group {
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
border-radius: 15px;
padding: 20px;
margin-bottom: 20px;
text-align: center;
transition: all 0.3s ease;
border: 2px solid transparent;
}
.form-group:hover {
transform: translateY(-5px);
box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3);
border-color: #667eea;
}
label {
display: block;
font-size: 0.85em;
color: #666;
text-transform: uppercase;
letter-spacing: 1.5px;
margin-bottom: 10px;
font-weight: 600;
}
input[type="text"] {
width: 100%;
padding: 12px;
border: none;
background: white;
border-radius: 10px;
font-size: 2em;
font-weight: bold;
color: #667eea;
text-align: center;
box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.1);
}
input[readonly] {
cursor: default;
}
button {
width: 100%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 20px 30px;
border-radius: 15px;
font-size: 1.1em;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
}
button:hover {
transform: translateY(-3px) scale(1.02);
box-shadow: 0 12px 30px rgba(102, 126, 234, 0.5);
}
h1 {
text-align: center;
color: white;
font-size: 3em;
margin-bottom: 40px;
text-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
letter-spacing: 1px;
}
.footer {
text-align: center;
color: white;
margin-top: 30px;
font-size: 0.95em;
opacity: 0.9;
}
</style>
</head>
<body>
<h1>🕐 TimeTrack Pro</h1>
<div class='form-section'>
<div class='section-title'>Tableau de Bord</div>
<div class='form-group'>
<label>Nombre de Clients</label>
<input type="text" id="txtNbClients" name="NbClients" readonly value="0">
</div>
<div class='form-group'>
<label>Projets Actifs</label>
<input type="text" id="txtNbProjets" name="NbProjets" readonly value="0">
</div>
<div class='form-group'>
<label>Heures ce Mois</label>
<input type="text" id="txtHeuresMois" name="HeuresMois" readonly value="0h">
</div>
<div class='form-group'>
<label>Total Heures</label>
<input type="text" id="txtTotalHeures" name="TotalHeures" readonly value="0h">
</div>
</div>
<div class='form-section'>
<div class='section-title'>Actions Rapides</div>
<div class='form-group'>
<button id="btnClients">👥 Gérer Clients</button>
</div>
<div class='form-group'>
<button id="btnProjets">📁 Gérer Projets</button>
</div>
<div class='form-group'>
<button id="btnSaisie">⏱️ Saisir Temps</button>
</div>
<div class='form-group'>
<button id="btnHistorique">📊 Voir Historique</button>
</div>
</div>
<div class="footer">
TimeTrack Pro v1.0 - Gestion professionnelle du temps
</div>
</body>
</html>

View File

@ -0,0 +1,220 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TimeTrack Pro - Gestion Clients</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 40px 20px;
}
.form-section {
background: white;
border-radius: 20px;
padding: 35px;
margin-bottom: 25px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
animation: slideIn 0.5s ease-out;
}
@keyframes slideIn {
from {
opacity: 0;
transform: translateX(-30px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.section-title {
color: #667eea;
font-size: 1.6em;
font-weight: bold;
margin-bottom: 25px;
padding-bottom: 12px;
border-bottom: 3px solid #667eea;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
color: #444;
font-weight: 600;
margin-bottom: 8px;
font-size: 0.95em;
letter-spacing: 0.5px;
}
input[type="text"],
input[type="email"],
input[type="tel"],
textarea {
width: 100%;
padding: 14px 18px;
border: 2px solid #e0e0e0;
border-radius: 12px;
font-size: 1em;
transition: all 0.3s ease;
font-family: inherit;
background: #f8f9fa;
}
input:focus,
textarea:focus {
outline: none;
border-color: #667eea;
background: white;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
transform: translateY(-2px);
}
textarea {
resize: vertical;
min-height: 120px;
}
button {
width: 100%;
padding: 14px 24px;
border: none;
border-radius: 12px;
font-size: 1em;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
button:hover {
transform: translateY(-3px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
}
#btnEnregistrer {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
#btnNouveau {
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
color: white;
}
#btnSupprimer {
background: linear-gradient(135deg, #eb3349 0%, #f45c43 100%);
color: white;
}
#btnRetour,
#btnPremier,
#btnPrecedent,
#btnSuivant,
#btnDernier {
background: linear-gradient(135deg, #757f9a 0%, #d7dde8 100%);
color: #333;
}
h1 {
text-align: center;
color: white;
font-size: 2.8em;
margin-bottom: 35px;
text-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
}
.required {
color: #eb3349;
margin-left: 3px;
}
.hint {
font-size: 0.85em;
color: #777;
font-style: italic;
margin-top: 5px;
}
</style>
</head>
<body>
<h1>👥 Gestion des Clients</h1>
<div class='form-section'>
<div class='section-title'>Informations Client</div>
<div class='form-group'>
<label>Nom du Client <span class="required">*</span></label>
<input type="text" id="txtNom" name="Nom" required maxlength="100" placeholder="Nom de l'entreprise ou du client">
</div>
<div class='form-group'>
<label>Email</label>
<input type="email" id="txtEmail" name="Email" maxlength="100" placeholder="contact@exemple.fr">
</div>
<div class='form-group'>
<label>Téléphone</label>
<input type="tel" id="txtTelephone" name="Telephone" maxlength="20" placeholder="01 23 45 67 89">
</div>
<div class='form-group'>
<label>Notes</label>
<textarea id="txtNotes" name="Notes" placeholder="Informations complémentaires, préférences, historique..."></textarea>
</div>
</div>
<div class='form-section'>
<div class='section-title'>Actions</div>
<div class='form-group'>
<button id="btnEnregistrer">💾 Enregistrer</button>
</div>
<div class='form-group'>
<button id="btnNouveau"> Nouveau</button>
</div>
<div class='form-group'>
<button id="btnSupprimer">🗑️ Supprimer</button>
</div>
<div class='form-group'>
<button id="btnRetour">↩️ Retour</button>
</div>
</div>
<div class='form-section'>
<div class='section-title'>Navigation</div>
<div class='form-group'>
<button id="btnPremier">⏮️ Premier</button>
</div>
<div class='form-group'>
<button id="btnPrecedent">◀️ Précédent</button>
</div>
<div class='form-group'>
<button id="btnSuivant">▶️ Suivant</button>
</div>
<div class='form-group'>
<button id="btnDernier">⏭️ Dernier</button>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,260 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TimeTrack Pro - Gestion Projets</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 40px 20px;
}
.form-section {
background: white;
border-radius: 20px;
padding: 35px;
margin-bottom: 25px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
animation: fadeIn 0.6s ease-out;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.section-title {
color: #667eea;
font-size: 1.6em;
font-weight: bold;
margin-bottom: 25px;
padding-bottom: 12px;
border-bottom: 3px solid #667eea;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
color: #444;
font-weight: 600;
margin-bottom: 8px;
font-size: 0.95em;
}
input[type="text"],
input[type="number"],
select,
textarea {
width: 100%;
padding: 14px 18px;
border: 2px solid #e0e0e0;
border-radius: 12px;
font-size: 1em;
transition: all 0.3s ease;
font-family: inherit;
background: #f8f9fa;
}
input:focus,
select:focus,
textarea:focus {
outline: none;
border-color: #667eea;
background: white;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
input[readonly] {
background: #e9ecef;
cursor: not-allowed;
}
textarea {
resize: vertical;
min-height: 100px;
}
input[type="checkbox"] {
width: 24px;
height: 24px;
cursor: pointer;
accent-color: #667eea;
}
button {
width: 100%;
padding: 14px 24px;
border: none;
border-radius: 12px;
font-size: 1em;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
margin-bottom: 12px;
}
button:hover {
transform: translateY(-3px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
}
#btnEnregistrer {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
#btnNouveau {
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
color: white;
}
#btnSupprimer {
background: linear-gradient(135deg, #eb3349 0%, #f45c43 100%);
color: white;
}
#btnRetour,
#btnPremier,
#btnPrecedent,
#btnSuivant,
#btnDernier {
background: linear-gradient(135deg, #757f9a 0%, #d7dde8 100%);
color: #333;
}
h1 {
text-align: center;
color: white;
font-size: 2.8em;
margin-bottom: 35px;
text-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
}
.stats-section {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
border-radius: 15px;
padding: 20px;
color: white;
box-shadow: 0 8px 20px rgba(240, 147, 251, 0.3);
}
.stats-section .section-title {
color: white;
border-bottom-color: white;
}
.stats-section input {
background: rgba(255, 255, 255, 0.2);
border: 2px solid rgba(255, 255, 255, 0.3);
color: white;
font-weight: bold;
}
.stats-section label {
color: white;
opacity: 0.9;
}
</style>
</head>
<body>
<h1>📁 Gestion des Projets</h1>
<div class='form-section'>
<div class='section-title'>Informations Projet</div>
<div class='form-group'>
<label>Client</label>
<select id="cboClient" name="ClientID" required>
<option value="">-- Sélectionner un client --</option>
</select>
</div>
<div class='form-group'>
<label>Nom du Projet</label>
<input type="text" id="txtNom" name="Nom" required maxlength="100" placeholder="Ex: Refonte site web">
</div>
<div class='form-group'>
<label>Description</label>
<textarea id="txtDescription" name="Description" placeholder="Description détaillée du projet..."></textarea>
</div>
<div class='form-group'>
<label>Taux Horaire (EUR)</label>
<input type="number" id="txtTauxHoraire" name="TauxHoraire" step="0.01" min="0" value="0" placeholder="75.00">
</div>
<div class='form-group'>
<label>Projet Actif</label>
<input type="checkbox" id="chkActif" name="Actif" checked>
</div>
</div>
<div class='form-section stats-section'>
<div class='section-title'>Statistiques Projet</div>
<div class='form-group'>
<label>Total Heures</label>
<input type="text" id="txtTotalHeures" name="TotalHeures" readonly value="0h">
</div>
<div class='form-group'>
<label>Montant Total</label>
<input type="text" id="txtMontantTotal" name="MontantTotal" readonly value="0.00 EUR">
</div>
</div>
<div class='form-section'>
<div class='section-title'>Actions</div>
<div class='form-group'>
<button id="btnEnregistrer">💾 Enregistrer</button>
</div>
<div class='form-group'>
<button id="btnNouveau"> Nouveau</button>
</div>
<div class='form-group'>
<button id="btnSupprimer">🗑️ Supprimer</button>
</div>
<div class='form-group'>
<button id="btnRetour">↩️ Retour</button>
</div>
</div>
<div class='form-section'>
<div class='section-title'>Navigation</div>
<div class='form-group'>
<button id="btnPremier">⏮️ Premier</button>
</div>
<div class='form-group'>
<button id="btnPrecedent">◀️ Précédent</button>
</div>
<div class='form-group'>
<button id="btnSuivant">▶️ Suivant</button>
</div>
<div class='form-group'>
<button id="btnDernier">⏭️ Dernier</button>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,280 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TimeTrack Pro - Saisie Temps</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 40px 20px;
}
.form-section {
background: white;
border-radius: 20px;
padding: 35px;
margin-bottom: 25px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
animation: bounceIn 0.6s ease-out;
}
@keyframes bounceIn {
0% {
opacity: 0;
transform: scale(0.8);
}
50% {
transform: scale(1.02);
}
100% {
opacity: 1;
transform: scale(1);
}
}
.section-title {
color: #667eea;
font-size: 1.6em;
font-weight: bold;
margin-bottom: 25px;
padding-bottom: 12px;
border-bottom: 3px solid #667eea;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
color: #444;
font-weight: 600;
margin-bottom: 8px;
font-size: 0.95em;
}
input[type="date"],
input[type="number"],
input[type="text"],
select,
textarea {
width: 100%;
padding: 14px 18px;
border: 2px solid #e0e0e0;
border-radius: 12px;
font-size: 1em;
transition: all 0.3s ease;
font-family: inherit;
background: #f8f9fa;
}
input:focus,
select:focus,
textarea:focus {
outline: none;
border-color: #667eea;
background: white;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
input[readonly] {
background: #e9ecef;
cursor: not-allowed;
}
textarea {
resize: vertical;
min-height: 100px;
}
button {
width: 100%;
padding: 14px 24px;
border: none;
border-radius: 12px;
font-size: 1em;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
margin-bottom: 12px;
}
button:hover {
transform: translateY(-3px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
}
.quick-btn {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
color: white;
}
#btnEnregistrer {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
#btnNouveau {
background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%);
color: white;
}
#btnRetour {
background: linear-gradient(135deg, #757f9a 0%, #d7dde8 100%);
color: #333;
}
h1 {
text-align: center;
color: white;
font-size: 2.8em;
margin-bottom: 35px;
text-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
}
.highlight-section {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
color: white;
}
.highlight-section .section-title {
color: white;
border-bottom-color: white;
}
.highlight-section label {
color: white;
opacity: 0.9;
}
.highlight-section input {
background: rgba(255, 255, 255, 0.2);
border: 2px solid rgba(255, 255, 255, 0.3);
color: white;
font-size: 2em;
font-weight: bold;
text-align: center;
}
.recap-section {
background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
}
.recap-section .section-title {
color: #f45c43;
border-bottom-color: #f45c43;
}
.recap-section label {
color: #333;
}
.recap-section input {
background: rgba(255, 255, 255, 0.5);
border-color: rgba(255, 255, 255, 0.8);
}
</style>
</head>
<body>
<h1>⏱️ Saisie de Temps</h1>
<div class='form-section'>
<div class='section-title'>Nouvelle Entrée</div>
<div class='form-group'>
<label>Projet</label>
<select id="cboProjet" name="ProjetID" required>
<option value="">-- Sélectionner un projet --</option>
</select>
</div>
<div class='form-group'>
<label>Date</label>
<input type="date" id="txtDate" name="Date" required>
</div>
<div class='form-group'>
<label>Durée (heures)</label>
<input type="number" id="txtDuree" name="Duree" required step="0.25" min="0.25" max="24" placeholder="3.5">
</div>
<div class='form-group'>
<label>Description</label>
<textarea id="txtDescription" name="Description" placeholder="Détaillez le travail effectué..."></textarea>
</div>
</div>
<div class='form-section'>
<div class='section-title'>Actions Rapides - Durée</div>
<div class='form-group'>
<button class="quick-btn" id="btn30min">30 min</button>
</div>
<div class='form-group'>
<button class="quick-btn" id="btn1h">1h</button>
</div>
<div class='form-group'>
<button class="quick-btn" id="btn2h">2h</button>
</div>
<div class='form-group'>
<button class="quick-btn" id="btn4h">4h</button>
</div>
<div class='form-group'>
<button class="quick-btn" id="btn8h">8h</button>
</div>
</div>
<div class='form-section highlight-section'>
<div class='section-title'>Calcul</div>
<div class='form-group'>
<label>Montant Calculé</label>
<input type="text" id="txtMontant" name="Montant" readonly value="0.00 EUR">
</div>
</div>
<div class='form-section'>
<div class='section-title'>Actions</div>
<div class='form-group'>
<button id="btnEnregistrer">💾 Enregistrer</button>
</div>
<div class='form-group'>
<button id="btnNouveau"> Nouvelle Entrée</button>
</div>
<div class='form-group'>
<button id="btnRetour">↩️ Retour</button>
</div>
</div>
<div class='form-section recap-section'>
<div class='section-title'>Récap du Jour</div>
<div class='form-group'>
<label>Entrées Aujourd'hui</label>
<input type="text" id="txtNbEntrees" name="NbEntrees" readonly value="0">
</div>
<div class='form-group'>
<label>Total Heures</label>
<input type="text" id="txtTotalJour" name="TotalJour" readonly value="0h">
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,283 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TimeTrack Pro - Historique</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 40px 20px;
}
.form-section {
background: white;
border-radius: 20px;
padding: 35px;
margin-bottom: 25px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
animation: slideRight 0.6s ease-out;
}
@keyframes slideRight {
from {
opacity: 0;
transform: translateX(50px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
.section-title {
color: #667eea;
font-size: 1.6em;
font-weight: bold;
margin-bottom: 25px;
padding-bottom: 12px;
border-bottom: 3px solid #667eea;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
color: #444;
font-weight: 600;
margin-bottom: 8px;
font-size: 0.95em;
}
input[type="date"],
input[type="text"],
select {
width: 100%;
padding: 14px 18px;
border: 2px solid #e0e0e0;
border-radius: 12px;
font-size: 1em;
transition: all 0.3s ease;
font-family: inherit;
background: #f8f9fa;
}
input:focus,
select:focus {
outline: none;
border-color: #667eea;
background: white;
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}
input[readonly] {
background: #e9ecef;
cursor: not-allowed;
}
button {
width: 100%;
padding: 14px 20px;
border: none;
border-radius: 12px;
font-size: 0.95em;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
margin-bottom: 12px;
}
button:hover {
transform: translateY(-3px);
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
}
#btnFiltrer {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
#btnExportPDF {
background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
color: white;
}
#btnExportExcel {
background: linear-gradient(135deg, #30cfd0 0%, #330867 100%);
color: white;
}
#btnRetour,
.preset-btn {
background: linear-gradient(135deg, #757f9a 0%, #d7dde8 100%);
color: #333;
}
h1 {
text-align: center;
color: white;
font-size: 2.8em;
margin-bottom: 35px;
text-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
}
.quick-filters-section {
background: linear-gradient(135deg, #e0c3fc 0%, #8ec5fc 100%);
}
.quick-filters-section .section-title {
color: #5e3da8;
border-bottom-color: #5e3da8;
}
.quick-filters-section .preset-btn {
background: white;
border: 2px solid #5e3da8;
color: #5e3da8;
}
.quick-filters-section .preset-btn:hover {
background: #5e3da8;
color: white;
}
.stats-section {
background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
}
.stats-section .section-title {
color: #333;
}
.stats-section label {
color: #333;
font-size: 0.8em;
text-transform: uppercase;
letter-spacing: 1px;
}
.stats-section input {
background: rgba(255, 255, 255, 0.6);
border-color: rgba(255, 255, 255, 0.8);
font-size: 1.8em;
font-weight: bold;
color: #667eea;
text-align: center;
}
</style>
</head>
<body>
<h1>📊 Historique et Rapports</h1>
<div class='form-section'>
<div class='section-title'>Filtres</div>
<div class='form-group'>
<label>Date Début</label>
<input type="date" id="txtDateDebut" name="DateDebut">
</div>
<div class='form-group'>
<label>Date Fin</label>
<input type="date" id="txtDateFin" name="DateFin">
</div>
<div class='form-group'>
<label>Client</label>
<select id="cboClient" name="ClientID">
<option value="">Tous les clients</option>
</select>
</div>
<div class='form-group'>
<label>Projet</label>
<select id="cboProjet" name="ProjetID">
<option value="">Tous les projets</option>
</select>
</div>
</div>
<div class='form-section'>
<div class='section-title'>Actions</div>
<div class='form-group'>
<button id="btnFiltrer">🔍 Filtrer</button>
</div>
<div class='form-group'>
<button id="btnExportPDF">📄 Export PDF</button>
</div>
<div class='form-group'>
<button id="btnExportExcel">📊 Export Excel</button>
</div>
<div class='form-group'>
<button id="btnRetour">↩️ Retour</button>
</div>
</div>
<div class='form-section quick-filters-section'>
<div class='section-title'>Filtres Rapides</div>
<div class='form-group'>
<button class="preset-btn" id="btnAujourdhui">📅 Aujourd'hui</button>
</div>
<div class='form-group'>
<button class="preset-btn" id="btnSemaine">📆 Cette Semaine</button>
</div>
<div class='form-group'>
<button class="preset-btn" id="btnMois">🗓️ Ce Mois</button>
</div>
<div class='form-group'>
<button class="preset-btn" id="btnMoisDernier">⬅️ Mois Dernier</button>
</div>
<div class='form-group'>
<button class="preset-btn" id="btnAnnee">📊 Cette Année</button>
</div>
<div class='form-group'>
<button class="preset-btn" id="btnTout">🌍 Tout</button>
</div>
</div>
<div class='form-section stats-section'>
<div class='section-title'>Statistiques</div>
<div class='form-group'>
<label>Entrées</label>
<input type="text" id="txtNbEntrees" name="NbEntrees" readonly value="0">
</div>
<div class='form-group'>
<label>Total Heures</label>
<input type="text" id="txtTotalHeures" name="TotalHeures" readonly value="0h">
</div>
<div class='form-group'>
<label>Montant Total</label>
<input type="text" id="txtMontantTotal" name="MontantTotal" readonly value="0.00 €">
</div>
<div class='form-group'>
<label>Moyenne / Jour</label>
<input type="text" id="txtMoyenne" name="Moyenne" readonly value="0h">
</div>
</div>
</body>
</html>

20
list_all_modules.vbs Normal file
View File

@ -0,0 +1,20 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
WScript.Echo "=== All VBA Components ==="
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
Dim comp
For Each comp In vbProj.VBComponents
WScript.Echo comp.Name & " - Type: " & comp.Type
Next
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing

50
rename_orphan_modules.vbs Normal file
View File

@ -0,0 +1,50 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
WScript.Echo "=== Renaming orphan Form_* Type 1 modules ==="
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
Dim modulesToRename
modulesToRename = Array("Form_frm_Accueil", "Form_frm_Clients", "Form_frm_Projets", "Form_frm_Historique")
Dim i
For i = LBound(modulesToRename) To UBound(modulesToRename)
Dim comp
Set comp = Nothing
Dim c
For Each c In vbProj.VBComponents
If c.Name = modulesToRename(i) And c.Type = 1 Then
Set comp = c
Exit For
End If
Next
If Not comp Is Nothing Then
Dim newName
newName = "OLD_" & modulesToRename(i)
WScript.Echo "Renaming: " & comp.Name & " -> " & newName
comp.Name = newName
WScript.Echo " -> Renamed!"
Else
WScript.Echo "Not found or not Type 1: " & modulesToRename(i)
End If
Next
WScript.Echo ""
WScript.Echo "=== Remaining Form_* modules ==="
For Each c In vbProj.VBComponents
If Left(c.Name, 5) = "Form_" Then
WScript.Echo c.Name & " - Type: " & c.Type
End If
Next
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing

12
run_fix_bindings.vbs Normal file
View File

@ -0,0 +1,12 @@
Dim accessApp
Set accessApp = GetObject(, "Access.Application")
On Error Resume Next
accessApp.Run "mod_FixFormBindings.FixAllFormBindings"
If Err.Number <> 0 Then
WScript.Echo "Error: " & Err.Description
WScript.Quit 1
Else
WScript.Echo "Success! Form bindings fixed."
End If

19
set_recordsource.vbs Normal file
View File

@ -0,0 +1,19 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
accessApp.Visible = False
' Fix frm_SaisieTemps RecordSource
accessApp.DoCmd.OpenForm "frm_SaisieTemps", 2 ' acDesign
WScript.Sleep 500
accessApp.Forms("frm_SaisieTemps").RecordSource = "tbl_Temps"
accessApp.DoCmd.Close 2, "frm_SaisieTemps", 1
WScript.Echo "frm_SaisieTemps RecordSource set to tbl_Temps"
' Cleanup
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing

24
test_button.vbs Normal file
View File

@ -0,0 +1,24 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
accessApp.Visible = True
' Ouvrir le formulaire Accueil
accessApp.DoCmd.OpenForm "frm_Accueil", 0 ' 0 = acNormal
WScript.Sleep 1000
' Declencher le clic sur le bouton
accessApp.Forms("frm_Accueil").btnClients.SetFocus
accessApp.Forms("frm_Accueil").btnClients_Click
WScript.Sleep 3000
' Attendre pour voir les messages
WScript.Echo "Test termine. Appuyez sur OK pour fermer."
accessApp.Quit
Set accessApp = Nothing

View File

@ -0,0 +1,52 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
accessApp.Visible = True
WScript.Echo "Creating test form..."
' Creer un formulaire simple
accessApp.DoCmd.NewObject 2, "frm_Test", "Normal" ' 2 = acForm
WScript.Sleep 1000
' Ouvrir en mode Design
accessApp.DoCmd.OpenForm "frm_Test", 2
WScript.Sleep 500
' Activer HasModule
WScript.Echo "Setting HasModule = True..."
accessApp.Forms("frm_Test").HasModule = True
If Err.Number = 0 Then
WScript.Echo "SUCCESS! HasModule activated for test form"
' Sauvegarder
accessApp.DoCmd.Close 2, "frm_Test", 1
WScript.Sleep 500
' Verifier
Dim vbProj
Set vbProj = accessApp.VBE.VBProjects(1)
Dim comp
For Each comp In vbProj.VBComponents
If comp.Name = "Form_frm_Test" Then
WScript.Echo "Module created! Type: " & comp.Type
Exit For
End If
Next
Else
WScript.Echo "FAILED: " & Err.Description
End If
WScript.Echo "Press OK to close."
accessApp.CloseCurrentDatabase
accessApp.Quit
Set accessApp = Nothing

38
test_direct_call.vbs Normal file
View File

@ -0,0 +1,38 @@
On Error Resume Next
Dim accessApp
Set accessApp = CreateObject("Access.Application")
accessApp.OpenCurrentDatabase "C:\Users\alexi\Documents\projects\timetrack-pro\db\TimeTrackPro.accdb"
accessApp.Visible = False
' Ouvrir le formulaire en mode normal
accessApp.DoCmd.OpenForm "frm_Accueil", 0 ' acNormal
WScript.Sleep 1000
' Essayer d'appeler directement la procedure
accessApp.Run "Form_frm_Accueil.btnClients_Click"
If Err.Number <> 0 Then
WScript.Echo "Erreur lors de l'appel: " & Err.Number & " - " & Err.Description
Err.Clear
End If
WScript.Sleep 2000
' Lire le log si créé
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FileExists("C:\Users\alexi\Documents\projects\timetrack-pro\button_log.txt") Then
Dim logFile
Set logFile = fso.OpenTextFile("C:\Users\alexi\Documents\projects\timetrack-pro\button_log.txt", 1)
WScript.Echo "LOG CONTENT:"
WScript.Echo logFile.ReadAll()
logFile.Close
Else
WScript.Echo "Aucun fichier log cree - le code n'a pas ete execute"
End If
accessApp.Quit
Set accessApp = Nothing