Compare commits

...

10 commits

Author SHA1 Message Date
ca3eb663fe 13-05-2026 Waren Wirtschaft 2026-05-13 18:09:20 +02:00
9ce711d6b2 April 2026 waren Wirtschaft Feedback 2026-04-10 17:14:38 +02:00
Kevin Adametz
02f2a4c23e commit 08-2025 2025-08-12 15:51:04 +02:00
Kevin Adametz
9b54eb0512 Updates to 03-2025 2025-04-01 10:39:21 +02:00
Kevin Adametz
6167273a48 Cron Jobs, Reminder, Fonts, Members / Wizard / Price, Credit and Promotion 2023-01-25 12:42:41 +01:00
Kevin Adametz
a0f4eda6ea testemich Promotion 2022-04-14 13:21:17 +02:00
Kevin Adametz
38e7fd504a 01 2022 Microsite Promotion 2022-01-18 18:30:14 +01:00
Kevin Adametz
3f1fb9377d Zugriff Redakteur, Kundenhoheit API 2022-01-04 11:17:07 +01:00
Kevin Adametz
570d428b1c promotion 1.0 2021-12-25 02:51:22 +01:00
Kevin Adametz
1cc8e025a1 Promotion Frontend dynamic 2021-11-26 18:23:10 +01:00
792 changed files with 92035 additions and 24475 deletions

18
.cursor/mcp.json Normal file
View file

@ -0,0 +1,18 @@
{
"mcpServers": {
"laravel-boost": {
"command": "php",
"args": [
"artisan",
"boost:mcp"
]
},
"sequential-thinking": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-sequential-thinking"
]
}
}
}

View file

@ -0,0 +1,248 @@
---
alwaysApply: true
---
<laravel-boost-guidelines>
=== foundation rules ===
# Laravel Boost Guidelines
The Laravel Boost guidelines are specifically curated by Laravel maintainers for this application. These guidelines should be followed closely to enhance the user's satisfaction building Laravel applications.
## Foundational Context
This application is a Laravel application and its main Laravel ecosystems package & versions are below. You are an expert with them all. Ensure you abide by these specific packages & versions.
- php - 8.4.1
- laravel/framework (LARAVEL) - v11
- laravel/prompts (PROMPTS) - v0
- laravel/pint (PINT) - v1
- pestphp/pest (PEST) - v2
## Conventions
- You must follow all existing code conventions used in this application. When creating or editing a file, check sibling files for the correct structure, approach, naming.
- Use descriptive names for variables and methods. For example, `isRegisteredForDiscounts`, not `discount()`.
- Check for existing components to reuse before writing a new one.
## Verification Scripts
- Do not create verification scripts or tinker when tests cover that functionality and prove it works. Unit and feature tests are more important.
## Application Structure & Architecture
- Stick to existing directory structure - don't create new base folders without approval.
- Do not change the application's dependencies without approval.
## Frontend Bundling
- If the user doesn't see a frontend change reflected in the UI, it could mean they need to run `npm run build`, `npm run dev`, or `composer run dev`. Ask them.
## Replies
- Be concise in your explanations - focus on what's important rather than explaining obvious details.
## Documentation Files
- You must only create documentation files if explicitly requested by the user.
=== boost rules ===
## Laravel Boost
- Laravel Boost is an MCP server that comes with powerful tools designed specifically for this application. Use them.
## Artisan
- Use the `list-artisan-commands` tool when you need to call an Artisan command to double check the available parameters.
## URLs
- Whenever you share a project URL with the user you should use the `get-absolute-url` tool to ensure you're using the correct scheme, domain / IP, and port.
## Tinker / Debugging
- You should use the `tinker` tool when you need to execute PHP to debug code or query Eloquent models directly.
- Use the `database-query` tool when you only need to read from the database.
## Reading Browser Logs With the `browser-logs` Tool
- You can read browser logs, errors, and exceptions using the `browser-logs` tool from Boost.
- Only recent browser logs will be useful - ignore old logs.
## Searching Documentation (Critically Important)
- Boost comes with a powerful `search-docs` tool you should use before any other approaches. This tool automatically passes a list of installed packages and their versions to the remote Boost API, so it returns only version-specific documentation specific for the user's circumstance. You should pass an array of packages to filter on if you know you need docs for particular packages.
- The 'search-docs' tool is perfect for all Laravel related packages, including Laravel, Inertia, Livewire, Filament, Tailwind, Pest, Nova, Nightwatch, etc.
- You must use this tool to search for Laravel-ecosystem documentation before falling back to other approaches.
- Search the documentation before making code changes to ensure we are taking the correct approach.
- Use multiple, broad, simple, topic based queries to start. For example: `['rate limiting', 'routing rate limiting', 'routing']`.
- Do not add package names to queries - package information is already shared. For example, use `test resource table`, not `filament 4 test resource table`.
### Available Search Syntax
- You can and should pass multiple queries at once. The most relevant results will be returned first.
1. Simple Word Searches with auto-stemming - query=authentication - finds 'authenticate' and 'auth'
2. Multiple Words (AND Logic) - query=rate limit - finds knowledge containing both "rate" AND "limit"
3. Quoted Phrases (Exact Position) - query="infinite scroll" - Words must be adjacent and in that order
4. Mixed Queries - query=middleware "rate limit" - "middleware" AND exact phrase "rate limit"
5. Multiple Queries - queries=["authentication", "middleware"] - ANY of these terms
=== php rules ===
## PHP
- Always use curly braces for control structures, even if it has one line.
### Constructors
- Use PHP 8 constructor property promotion in `__construct()`.
- <code-snippet>public function __construct(public GitHub $github) { }</code-snippet>
- Do not allow empty `__construct()` methods with zero parameters.
### Type Declarations
- Always use explicit return type declarations for methods and functions.
- Use appropriate PHP type hints for method parameters.
<code-snippet name="Explicit Return Types and Method Params" lang="php">
protected function isAccessible(User $user, ?string $path = null): bool
{
...
}
</code-snippet>
## Comments
- Prefer PHPDoc blocks over comments. Never use comments within the code itself unless there is something _very_ complex going on.
## PHPDoc Blocks
- Add useful array shape type definitions for arrays when appropriate.
## Enums
- Typically, keys in an Enum should be TitleCase. For example: `FavoritePerson`, `BestLake`, `Monthly`.
=== laravel/core rules ===
## Do Things the Laravel Way
- Use `php artisan make:` commands to create new files (i.e. migrations, controllers, models, etc.). You can list available Artisan commands using the `list-artisan-commands` tool.
- If you're creating a generic PHP class, use `artisan make:class`.
- Pass `--no-interaction` to all Artisan commands to ensure they work without user input. You should also pass the correct `--options` to ensure correct behavior.
### Database
- Always use proper Eloquent relationship methods with return type hints. Prefer relationship methods over raw queries or manual joins.
- Use Eloquent models and relationships before suggesting raw database queries
- Avoid `DB::`; prefer `Model::query()`. Generate code that leverages Laravel's ORM capabilities rather than bypassing them.
- Generate code that prevents N+1 query problems by using eager loading.
- Use Laravel's query builder for very complex database operations.
### Model Creation
- When creating new models, create useful factories and seeders for them too. Ask the user if they need any other things, using `list-artisan-commands` to check the available options to `php artisan make:model`.
### APIs & Eloquent Resources
- For APIs, default to using Eloquent API Resources and API versioning unless existing API routes do not, then you should follow existing application convention.
### Controllers & Validation
- Always create Form Request classes for validation rather than inline validation in controllers. Include both validation rules and custom error messages.
- Check sibling Form Requests to see if the application uses array or string based validation rules.
### Queues
- Use queued jobs for time-consuming operations with the `ShouldQueue` interface.
### Authentication & Authorization
- Use Laravel's built-in authentication and authorization features (gates, policies, Sanctum, etc.).
### URL Generation
- When generating links to other pages, prefer named routes and the `route()` function.
### Configuration
- Use environment variables only in configuration files - never use the `env()` function directly outside of config files. Always use `config('app.name')`, not `env('APP_NAME')`.
### Testing
- When creating models for tests, use the factories for the models. Check if the factory has custom states that can be used before manually setting up the model.
- Faker: Use methods such as `$this->faker->word()` or `fake()->randomDigit()`. Follow existing conventions whether to use `$this->faker` or `fake()`.
- When creating tests, make use of `php artisan make:test [options] <name>` to create a feature test, and pass `--unit` to create a unit test. Most tests should be feature tests.
### Vite Error
- If you receive an "Illuminate\Foundation\ViteException: Unable to locate file in Vite manifest" error, you can run `npm run build` or ask the user to run `npm run dev` or `composer run dev`.
=== laravel/v11 rules ===
## Laravel 11
- Use the `search-docs` tool to get version specific documentation.
- This project upgraded from Laravel 10 without migrating to the new streamlined Laravel 11 file structure.
- This is **perfectly fine** and recommended by Laravel. Follow the existing structure from Laravel 10. We do not to need migrate to the Laravel 11 structure unless the user explicitly requests that.
### Laravel 10 Structure
- Middleware typically live in `app/Http/Middleware/` and service providers in `app/Providers/`.
- There is no `bootstrap/app.php` application configuration in a Laravel 10 structure:
- Middleware registration is in `app/Http/Kernel.php`
- Exception handling is in `app/Exceptions/Handler.php`
- Console commands and schedule registration is in `app/Console/Kernel.php`
- Rate limits likely exist in `RouteServiceProvider` or `app/Http/Kernel.php`
### Database
- When modifying a column, the migration must include all of the attributes that were previously defined on the column. Otherwise, they will be dropped and lost.
- Laravel 11 allows limiting eagerly loaded records natively, without external packages: `$query->latest()->limit(10);`.
### Models
- Casts can and likely should be set in a `casts()` method on a model rather than the `$casts` property. Follow existing conventions from other models.
### New Artisan Commands
- List Artisan commands using Boost's MCP tool, if available. New commands available in Laravel 11:
- `php artisan make:enum`
- `php artisan make:class`
- `php artisan make:interface`
=== pint/core rules ===
## Laravel Pint Code Formatter
- You must run `vendor/bin/pint --dirty` before finalizing changes to ensure your code matches the project's expected style.
- Do not run `vendor/bin/pint --test`, simply run `vendor/bin/pint` to fix any formatting issues.
=== pest/core rules ===
## Pest
### Testing
- If you need to verify a feature is working, write or update a Unit / Feature test.
### Pest Tests
- All tests must be written using Pest. Use `php artisan make:test --pest <name>`.
- You must not remove any tests or test files from the tests directory without approval. These are not temporary or helper files - these are core to the application.
- Tests should test all of the happy paths, failure paths, and weird paths.
- Tests live in the `tests/Feature` and `tests/Unit` directories.
- Pest tests look and behave like this:
<code-snippet name="Basic Pest Test Example" lang="php">
it('is true', function () {
expect(true)->toBeTrue();
});
</code-snippet>
### Running Tests
- Run the minimal number of tests using an appropriate filter before finalizing code edits.
- To run all tests: `php artisan test`.
- To run all tests in a file: `php artisan test tests/Feature/ExampleTest.php`.
- To filter on a particular test name: `php artisan test --filter=testName` (recommended after making a change to a related file).
- When the tests relating to your changes are passing, ask the user if they would like to run the entire test suite to ensure everything is still passing.
### Pest Assertions
- When asserting status codes on a response, use the specific method like `assertForbidden` and `assertNotFound` instead of using `assertStatus(403)` or similar, e.g.:
<code-snippet name="Pest Example Asserting postJson Response" lang="php">
it('returns all', function () {
$response = $this->postJson('/api/docs', []);
$response->assertSuccessful();
});
</code-snippet>
### Mocking
- Mocking can be very helpful when appropriate.
- When mocking, you can use the `Pest\Laravel\mock` Pest function, but always import it via `use function Pest\Laravel\mock;` before using it. Alternatively, you can use `$this->mock()` if existing tests do.
- You can also create partial mocks using the same import or self method.
### Datasets
- Use datasets in Pest to simplify tests which have a lot of duplicated data. This is often the case when testing validation rules, so consider going with this solution when writing tests for validation rules.
<code-snippet name="Pest Dataset Example" lang="php">
it('has emails', function (string $email) {
expect($email)->not->toBeEmpty();
})->with([
'james' => 'james@laravel.com',
'taylor' => 'taylor@laravel.com',
]);
</code-snippet>
</laravel-boost-guidelines>

View file

@ -0,0 +1,45 @@
{
"name": "Partner Grüne Seele (Dev Container)",
"dockerComposeFile": [
"../docker-compose.yml"
],
"service": "laravel.test",
"workspaceFolder": "/var/www/html",
"remoteUser": "sail",
"features": {},
"customizations": {
"vscode": {
"extensions": [
"bmewburn.vscode-intelephense-client",
"onecentlin.laravel-blade",
"shufo.vscode-blade-formatter",
"bradlc.vscode-tailwindcss",
"Anthropic.claude-code",
"onecentlin.laravel-extension-pack"
]
}
},
// WICHTIG: Nur noch den Haupt-Container starten!
"runServices": [
"laravel.test"
],
"containerEnv": {
"WWWUSER": "501",
"WWWGROUP": "20",
"LARAVEL_SAIL": "1"
},
"mounts": [
"source=${localWorkspaceFolder},target=/var/www/html,type=bind,consistency=cached",
"source=/Users/pandora/Library/Mobile Documents/iCloud~md~obsidian/Documents/DEV-Vault/gruene-seele,target=/var/www/html/docs,type=bind",
],
// WICHTIG: Nur noch den Vite-Port weiterleiten
"forwardPorts": [
5179
],
"portsAttributes": {
"5179": {
"label": "Vite Dev Server",
"onAutoForward": "notify"
}
}
}

68
.env
View file

@ -3,31 +3,39 @@ APP_ENV=local
APP_KEY=base64:w0K6RjfleoAOpuICea14JnaZ28PNc6EMzIFMQZ3MVtU=
APP_DEBUG=true
APP_URL=https://partner.gruene-seele.test
APP_API_DOMAIN=partner.gruene-seele.test
APP_DOMAIN=partner.gruene-seele.test
APP_PROMO_URL=https://testemich.test
APP_PROMO_DOMAIN=testemich.test
APP_CHECKOUT_MAIL=register@adametz.media
APP_CHECKOUT_TEST_MAIL=register@adametz.media
APP_INFO_MAIL=register@adametz.media
APP_INFO_TEST_MAIL=register@adametz.media
APP_SHOP_URL=https://grueneseele.test
APP_SHOP_DOMAIN=grueneseele.test
APP_CHECKOUT_MAIL=kevin.adametz@me.com
APP_CHECKOUT_TEST_MAIL=register@adametz.media
APP_INFO_MAIL=kevin.adametz@me.com
APP_INFO_TEST_MAIL=register@adametz.media
EXCEPTION_MAIL=exception@adametz.media
LOGISTIC_MAIL=kevin.adametz@me.com
APP_MAIN_TAX = 1.19
APP_MAIN_TAX_RATE = 19
APP_MAIN_USER_ID = 2
LOG_CHANNEL=stack
LOG_LEVEL=debug
DB_CONNECTION=mysql
DB_HOST=192.168.1.8
DB_HOST=mysql
DB_PORT=3306
DB_DATABASE=grueneseele
DB_USERNAME=kadmin
DB_PASSWORD=KT32vQ7ix
DB_DATABASE=partner_gruene_seele
DB_USERNAME=root
DB_PASSWORD=password
#DB_CONNECTION=mysql
#DB_HOST=localhost
#DB_HOST=mysql
#DB_PORT=3306
#DB_DATABASE=web28_db4
#DB_USERNAME=web28_4
@ -43,16 +51,40 @@ MEMCACHED_HOST=127.0.0.1
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
REDIS_PORT=6384
#REDIS_PORT=6379
MAIL_DRIVER=smtp
MAIL_HOST=mailpit
MAIL_PORT=1029
#MAIL_DRIVER=smtp
#MAIL_HOST=w017e534.kasserver.com
#MAIL_PORT=587
#MAIL_USERNAME=m0496c96
#MAIL_PASSWORD=mZtVp7WQcs6DC3hf
#MAIL_ENCRYPTION=null
#MAIL_FROM_ADDRESS=dev@adametz.media
#MAIL_FROM_NAME="DEV Grüne Seele"
#MAIL_MAILER=smtp
#MAIL_HOST=s182.goserver.host
#MAIL_PORT=587
#MAIL_USERNAME=web28p3
#MAIL_PASSWORD=WeE2bmI9GjB7pDgi
#MAIL_ENCRYPTION=""
#MAIL_FROM_ADDRESS=partner@gruene-seele.bio
#MAIL_FROM_NAME="GRÜNE SEELE Naturkosmetik"
RECAPTCHA_SITE_KEY="6LcGr_kqAAAAAOnz-L6IIBC_fTzJ7siTheZgFVMY"
RECAPTCHA_SECRET_KEY="6LcGr_kqAAAAAKBZVoy37ski0Gl54jenWOlrbc9z"
PAYPAL_MODE=sandbox
PAYPAL_SANDBOX_CLIENT_ID=AWMeW59cMOHaMWfv44kIMnzaR81Qo4yNVzEC5LyWl7x5RjkJZOJmvbvljqWPNEw7GihF3FLRL_tEJPHo
PAYPAL_SANDBOX_CLIENT_SECRET=EFOuvQJpx3lM2HjLjPURgcxKuGLtKxNHKZqx65uQpQ8WNLDvijHhb79X5oE22LKIwW5V0GdX09jI24bF
PAYPAL_LIVE_CLIENT_ID=ATBZUigDw1yuakQj9X7semskqBrBxSV3bOjp3AtHV5pCSc3tOIm1m2s3toUfGW9lcxQJ5_fSS37FVbki
PAYPAL_LIVE_CLIENT_SECRET=ECCH1CPCiHLzEMbl3rMSo1PVSqn2iqu59t-ZUXSx4p1J_tTklpl9QGkBN77s9DfCA1dQ6u7VfBBfPApn
MAIL_MAILER=smtp
MAIL_HOST=s182.goserver.host
MAIL_PORT=587
MAIL_USERNAME=web28p3
MAIL_PASSWORD=WeE2bmI9GjB7pDgi
MAIL_ENCRYPTION=""
MAIL_FROM_ADDRESS=partner@gruene-seele.bio
MAIL_FROM_NAME="Partner GRÜNE SEELE Naturkosmetik"
AWS_ACCESS_KEY_ID=
AWS_SECRET_ACCESS_KEY=

27
.mcp.json Normal file
View file

@ -0,0 +1,27 @@
{
"mcpServers": {
"laravel-boost": {
"command": "php",
"args": [
"artisan",
"boost:mcp"
]
},
"context7": {
"command": "npx",
"args": [
"-y",
"@upstash/context7-mcp",
"--api-key",
"ctx7sk-119cd4ab-8983-4229-8702-e84c59c34fc9"
]
},
"sequential-thinking": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-sequential-thinking"
]
}
}
}

39
.php-cs-fixer.php Normal file
View file

@ -0,0 +1,39 @@
<?php
$finder = PhpCsFixer\Finder::create()
->in([
__DIR__ . '/app',
__DIR__ . '/config',
__DIR__ . '/database',
__DIR__ . '/resources',
__DIR__ . '/routes',
__DIR__ . '/tests',
])
->name('*.php')
->notName('*.blade.php')
->ignoreDotFiles(true)
->ignoreVCS(true);
return (new PhpCsFixer\Config())
->setRules([
'@PSR2' => true,
'array_syntax' => ['syntax' => 'short'],
'ordered_imports' => ['sort_algorithm' => 'alpha'],
'no_unused_imports' => true,
'not_operator_with_successor_space' => true,
'trailing_comma_in_multiline' => true,
'phpdoc_scalar' => true,
'unary_operator_spaces' => true,
'binary_operator_spaces' => true,
'blank_line_before_statement' => [
'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'],
],
'phpdoc_single_line_var_spacing' => true,
'phpdoc_var_without_name' => true,
'method_argument_space' => [
'on_multiline' => 'ensure_fully_multiline',
'keep_multiple_spaces_after_comma' => true,
],
'single_trait_insert_per_statement' => true,
])
->setFinder($finder);

File diff suppressed because it is too large Load diff

85
CLAUDE.md Normal file
View file

@ -0,0 +1,85 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
German-language MLM/direct-sales e-commerce platform for organic/natural products ("Gruene Seele" / Green Soul). Partners/distributors get personal whitelabel shops, earn commissions through a multi-level hierarchy, and manage orders, invoices, and promotions.
**Stack:** PHP 8.4, Laravel 11 (using Laravel 10 directory structure), Bootstrap 4, jQuery, Laravel Mix (webpack), MySQL, Laravel Passport (API auth).
## Common Commands
```bash
# Tests (Pest v2, uses SQLite in-memory)
php artisan test # run all tests
php artisan test tests/Feature/ExampleTest.php # run single file
php artisan test --filter=testName # filter by name
# Code formatting (Laravel Pint)
vendor/bin/pint --dirty # format changed files only
vendor/bin/pint # format all files
composer format # alias for pint
# Frontend (Laravel Mix, NOT Vite)
npm run dev # development build
npm run prod # production build
npm run watch # watch mode
# Artisan - always pass --no-interaction
php artisan make:model Name --no-interaction
php artisan make:test --pest Name --no-interaction
```
## Architecture
### Multi-Domain Routing (`routes/web.php`)
Three separate domain groups, each with distinct middleware:
- **Main domain** (`config('app.domain')`) - admin panel + user dashboard
- **Promo domain** (`config('app.promo_domain')`) - public promotion/microsite pages
- **Shop domain** (`config('app.shop_domain')`) - public whitelabel shop
### Admin Access Levels (middleware in `app/Http/Middleware/`)
- `CopyReader` - admin >= 1 (product/content management)
- `Admin` - admin >= 7 (sales, customers, promotions)
- `SuperAdmin` - admin >= 8 (users, shipping, settings)
- `SysAdmin` - admin >= 9 (system tools, imports)
### Key Service Layer
- **`app/Services/Yard.php`** + `app/Services/Yard/` - Custom shopping cart (extends forked Gloudemans Cart in `packages/digital-bird/shoppingcart/`). Handles shipping, tax, margins, commissions.
- **`app/Services/Invoice.php`** - Invoice and cancellation invoice PDF generation (uses DomPDF)
- **`app/Services/PaymentReminderService.php`** - Payment reminder logic with status progression
- **`app/Services/Credit.php`** - User credit/balance management
- **`app/Services/Stats/`** - Sales statistics
### Repository Pattern
Business logic uses repositories in `app/Repositories/` (e.g., `CheckoutRepository`, `InvoiceRepository`, `CustomerRepository`). Controllers delegate to repositories and services.
### Local Packages
`packages/digital-bird/shoppingcart/` - Forked `gloudemans/shoppingcart`, autoloaded via composer PSR-4 as `Gloudemans\Shoppingcart\`.
### Cron Jobs (`app/Console/Kernel.php`)
- `payments:accounts` - Checks user account expiry, sends reminders (statuses 31/33/34/35), deactivates expired accounts
- `payments:reminders` - Sends payment reminders for open invoices
### API (`routes/api.php`)
No versioning. Passport-authenticated endpoints for WordPress integration (`/api/wp/*`) and auth (`/api/auth/*`).
### Global Helpers
`app/helpers.php` (autoloaded) - URL helpers, formatting delegates to `App\Services\Util`.
### PDF Generation
- `app/Libraries/InvoicePDF.php`, `ContractPDF.php` - FPDF/FPDI based
- `app/Services/Invoice.php` - DomPDF based (Blade templates in `resources/views/pdf/`)
## Important Conventions
- This project uses **Laravel 10 directory structure** on Laravel 11. Do NOT migrate to Laravel 11 structure.
- Middleware registration: `app/Http/Kernel.php`
- Exception handling: `app/Exceptions/Handler.php`
- Schedule: `app/Console/Kernel.php`
- Default auth guard is `user` (not `web`), configured in `config/auth.php`
- User model is `App\User` (not `App\Models\User`)
- Views are Blade templates with Bootstrap 4 + jQuery DataTables
- Always run `vendor/bin/pint --dirty` before finalizing changes
- Countries supported: DE, FR, CH, NL (with reverse charge VAT handling)

249
PAYMENT_REMINDER_CRON.md Normal file
View file

@ -0,0 +1,249 @@
# Payment Reminder Cron-Job Einrichtung
## Übersicht
Der `PaymentsReminders` Command automatisiert das Senden von Zahlungserinnerungen basierend auf den konfigurierten Intervallen in der Datenbank.
## Command ausführen
```bash
php artisan payments:reminders
```
## Cron-Job Konfiguration
### 1. Crontab öffnen
```bash
crontab -e
```
### 2. Cron-Job hinzufügen
**Täglich um 9:00 Uhr:**
```bash
0 9 * * * cd /path/to/your/project && php artisan payments:reminders >> /dev/null 2>&1
```
**Stündlich:**
```bash
0 * * * * cd /path/to/your/project && php artisan payments:reminders >> /dev/null 2>&1
```
**Alle 6 Stunden:**
```bash
0 */6 * * * cd /path/to/your/project && php artisan payments:reminders >> /dev/null 2>&1
```
### 3. Cron-Job testen
```bash
# Teste den Command manuell
php artisan payments:reminders
# Prüfe die Logs
tail -f storage/logs/laravel.log
```
## Funktionsweise
### 1. Intervall-basierte Verarbeitung
- Der Command holt alle aktiven `PaymentReminder` aus der Datenbank
- Gruppiert sie nach `clearingtype` (z.B. 'invoice', 'prepayment')
- Verwendet das kleinste Intervall pro `clearingtype`
### 2. Zahlungsprüfung
- Sucht offene Zahlungen, die älter als das konfigurierte Intervall sind
- Berücksichtigt nur die neueste Zahlung pro Bestellung
- Prüft nur Live-Zahlungen (nicht Test)
### 3. Erinnerungslogik
- **Erste Erinnerung**: Nach X Tagen ab Bestelldatum
- **Weitere Erinnerungen**: Nach Y Tagen ab letzter Erinnerung
- Stoppt wenn alle konfigurierten Erinnerungen gesendet wurden
### 4. Automatische Aktionen
- E-Mail-Versand mit Platzhalter-Ersetzung
- Optional: Bestellung auf "Storniert" setzen
- Optional: Payment auf "non" Status setzen
- Logging aller Aktivitäten
## Logging
### Command-Logs
```bash
# Live-Logs während der Ausführung
php artisan payments:reminders
# Beispiel-Output:
RUN Command Payments Reminders: 15.12.2024 09:00
=== STARTE PAYMENT REMINDERS ===
Gefundene aktive PaymentReminder: 3
Gefundene clearingtypes mit kleinsten Intervallen:
- invoice: 7 Tage
- prepayment: 3 Tage
--- Verarbeite clearingtype: invoice mit Intervall: 7 Tage ---
Suche Zahlungen vor: 08.12.2024 09:00:00
Gefundene offene Zahlungen für invoice: 5
Verarbeite Order ID: 12345, Created: 05.12.2024 10:30:00, Amount: 5000, Reminder: 0
📧 Sende Erinnerung...
✅ Erinnerung erfolgreich gesendet
=== PAYMENT REMINDERS ABGESCHLOSSEN ===
Ausführungszeit: 2.34 Sekunden
Statistiken:
- Gesamt verarbeitet: 5
- Erinnerungen gesendet: 3
- Fehler: 0
- Übersprungen: 2
```
### Laravel-Logs
```bash
# Logs in storage/logs/laravel.log
tail -f storage/logs/laravel.log | grep "Payment reminder"
```
## Konfiguration
### PaymentReminder Einstellungen
```sql
-- Beispiel-Konfiguration
INSERT INTO payment_reminders (clearingtype, interval, subject, message, action, active) VALUES
('invoice', 7, 'Zahlungserinnerung - Bestellung {order_number}', 'Sehr geehrte/r {billing_first_name}...', NULL, 1),
('invoice', 14, '2. Zahlungserinnerung - Bestellung {order_number}', 'Sehr geehrte/r {billing_first_name}...', NULL, 1),
('invoice', 21, 'Letzte Zahlungserinnerung - Bestellung {order_number}', 'Sehr geehrte/r {billing_first_name}...', 'set_order_status_cancelled', 1);
```
### Platzhalter
- `{billing_first_name}` - Vorname
- `{billing_last_name}` - Nachname
- `{order_number}` - Bestellnummer
- `{order_date}` - Bestelldatum
- `{order_total}` - Bestellsumme
## Monitoring
### 1. Log-Statistiken
- Admin-Bereich: `/admin/payments/reminder/logs`
- Zeigt Statistiken der letzten 7, 30 und 90 Tage
- Filter nach Order ID, Aktion und Datum
### 2. Erfolgsrate
- E-Mails gesendet vs. Fehler
- Aktionen ausgeführt
- Übersprungene Erinnerungen
### 3. Performance
- Ausführungszeit pro Lauf
- Anzahl verarbeiteter Zahlungen
- Speicherverbrauch
## Troubleshooting
### Häufige Probleme
**1. Command läuft nicht**
```bash
# Prüfe PHP-Pfad
which php
# Prüfe Projekt-Pfad
pwd
# Teste Command manuell
php artisan payments:reminders
```
**2. Keine E-Mails werden gesendet**
```bash
# Prüfe Mail-Konfiguration
php artisan config:cache
# Prüfe Logs
tail -f storage/logs/laravel.log
```
**3. Falsche Intervalle**
```bash
# Prüfe PaymentReminder-Konfiguration
php artisan tinker
>>> App\Models\PaymentReminder::where('active', true)->get()
```
**4. Cron-Job läuft nicht**
```bash
# Prüfe Crontab
crontab -l
# Prüfe Cron-Logs
sudo tail -f /var/log/cron
# Teste mit absoluten Pfaden
0 9 * * * /usr/bin/php /path/to/project/artisan payments:reminders
```
## Sicherheit
### 1. Berechtigungen
```bash
# Stelle sicher, dass der Webserver-Benutzer Schreibrechte hat
chown -R www-data:www-data storage/logs
chmod -R 755 storage/logs
```
### 2. Log-Rotation
```bash
# Konfiguriere Log-Rotation in /etc/logrotate.d/laravel
/path/to/project/storage/logs/*.log {
daily
missingok
rotate 52
compress
notifempty
create 644 www-data www-data
}
```
### 3. Backup
```bash
# Backup der PaymentReminder-Konfiguration
mysqldump -u username -p database payment_reminders > payment_reminders_backup.sql
```
## Performance-Optimierung
### 1. Batch-Verarbeitung
- Der Command verarbeitet Zahlungen in Batches
- Verwendet Datenbank-Indizes für bessere Performance
### 2. Memory-Management
- Garbage Collection nach jeder Zahlung
- Begrenzte Anzahl von Logs
### 3. Timeout-Handling
- Lange Ausführungen werden abgebrochen
- Fehler werden geloggt und übersprungen

File diff suppressed because it is too large Load diff

2267
_ide_helper_models.php Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,203 @@
<?php
namespace App\Console\Commands;
use App\User;
use Carbon\Carbon;
use Illuminate\Console\Command;
use App\Cron\UserCheckPaymentsAccounts;
class PaymentsAccounts extends Command
{
/**
* ln -sfv /usr/bin/php73 /usr/bin/php
* php artisan payments:accounts
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'payments:accounts';
protected $description = 'Check Payments Accounts';
private $timeStart;
private $dev = false;
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
\Log::info('Starting PaymentsAccounts Command', ['timestamp' => now()]);
$this->info('RUN Command Payments Account: '.date('d.m.Y H:i'));
$this->timeStart = microtime(true);
try {
$this->updateUserNextLevel();
$this->updatePaymentsAccountsFree();
$this->deactivateUserAccounts();
$this->reminderPaymentsAccounts();
\Log::info('PaymentsAccounts Command completed successfully');
return 0;
} catch (\Exception $e) {
\Log::error('PaymentsAccounts Command failed', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
return 1;
}
}
private function updateUserNextLevel(){
try {
// now date - renewal_days
$count = 0;
$renewalDate = Carbon::now()->modify('+'.(config('main.renewal_days')).' days');
$users = User::where('payment_account', '!=', NULL)
->where('active', '=', 1)
->where('blocked', '!=', 1)
->where('payment_account', '<', $renewalDate)
->whereColumn('m_level', '!=', 'next_m_level')
->where('deleted_at', NULL)
->get();
foreach($users as $user){
$user->m_level = $user->next_m_level;
$user->save();
$count ++;
}
$diff = microtime(true) - $this->timeStart;
$sec = intval($diff);
$micro = $diff - $sec;
$this->info('END Command updateUserNextLevel: '.$count.' | Time: '.$sec. 'sec :' . round($micro * 1000, 4) . " ms");
\Log::info('updateUserNextLevel completed', [
'users_updated' => $count,
'execution_time' => $sec . 'sec :' . round($micro * 1000, 4) . "ms"
]);
} catch (\Exception $e) {
\Log::error('updateUserNextLevel failed', [
'error' => $e->getMessage()
]);
throw $e;
}
}
private function updatePaymentsAccountsFree(){
try {
// now date - renewal_days -1 / user_levels.payment_year false is no payment
$count = 0;
$renewalDate = Carbon::now()->modify('+'.(config('main.renewal_days')-1).' days');
$users = User::join('user_levels', 'm_level', '=', 'user_levels.id')->select('users.*')
->where('users.payment_account', '!=', NULL)
->where('users.active', '=', 1)
->where('users.blocked', '!=', 1)
->where('users.payment_account', '<', $renewalDate)
->where('user_levels.payment_year', '=', 0)//user_levels.payment_year false is no payment
->where('users.deleted_at', NULL)
->get();
foreach($users as $user){
$user->payment_account = Carbon::parse($user->payment_account)->modify('1 year');
$user->save();
$count ++;
}
$diff = microtime(true) - $this->timeStart;
$sec = intval($diff);
$micro = $diff - $sec;
$this->info('END Command updatePaymentsAccountsFree: '.$count.' | Time: '.$sec. 'sec :' . round($micro * 1000, 4) . " ms");
\Log::info('updatePaymentsAccountsFree completed', [
'users_updated' => $count,
'execution_time' => $sec . 'sec :' . round($micro * 1000, 4) . "ms"
]);
} catch (\Exception $e) {
\Log::error('updatePaymentsAccountsFree failed', [
'error' => $e->getMessage()
]);
throw $e;
}
}
private function deactivateUserAccounts(){
try {
$count = 0;
$sevenDaysAfterExpiry = Carbon::now()->subDays(7);
$users = User::where('payment_account', '!=', NULL)
->where('active', '=', 1)
->where('blocked', '!=', 1)
->where('payment_account', '<', $sevenDaysAfterExpiry)
->where('deleted_at', NULL)
->get();
foreach($users as $user){
$user->active = 0;
$user->save();
$this->info('deactivateUserAccount | User: '.$user->id.' '.$user->email.' | Date :' . $user->getPaymentAccountDateFormat() . "");
$count ++;
}
$diff = microtime(true) - $this->timeStart;
$sec = intval($diff);
$micro = $diff - $sec;
$this->info('END Command deactivateUserAccounts: '.$count.' | Time: '.$sec. 'sec :' . round($micro * 1000, 4) . " ms");
\Log::info('deactivateUserAccounts completed', [
'users_updated' => $count,
'execution_time' => $sec . 'sec :' . round($micro * 1000, 4) . "ms"
]);
} catch (\Exception $e) {
\Log::error('deactivateUserAccounts failed', [
'error' => $e->getMessage()
]);
throw $e;
}
}
private function reminderPaymentsAccounts()
{
try {
$count = 0;
$max_reminder_date = Carbon::now()->modify('+'.(config('main.remind_first_days')).' days');
$users = User::where('payment_account', '!=', NULL)
->where('active', '=', 1)
->where('blocked', '!=', 1)
->where('payment_account', '<', $max_reminder_date)
->where('deleted_at', NULL)
->get();
foreach ($users as $user){
$status = UserCheckPaymentsAccounts::userReminderPayments($user, $this->dev);
$this->info('reminderPaymentsAccounts Status: '.$status.' | User: '.$user->id.' '.$user->email.' | Date :' . $user->getPaymentAccountDateFormat() . "");
$count ++;
}
$diff = microtime(true) - $this->timeStart;
$sec = intval($diff);
$micro = $diff - $sec;
$this->info('END Command reminderPaymentsAccounts: '.$count.' | Time: '.$sec. 'sec :' . round($micro * 1000, 4) . " ms");
\Log::info('reminderPaymentsAccounts completed', [
'users_processed' => $count,
'execution_time' => $sec . 'sec :' . round($micro * 1000, 4) . "ms"
]);
} catch (\Exception $e) {
\Log::error('reminderPaymentsAccounts failed', [
'error' => $e->getMessage()
]);
throw $e;
}
}
}

View file

@ -0,0 +1,279 @@
<?php
namespace App\Console\Commands;
use App\Models\PaymentReminder;
use App\Models\ShoppingPayment;
use App\Services\PaymentReminderService;
use Carbon\Carbon;
use Illuminate\Console\Command;
/**
* Command für automatische Zahlungserinnerungen
*
* Dieser Command wird als Cron-Job ausgeführt und sendet automatisch
* Zahlungserinnerungen basierend auf den konfigurierten Intervallen.
*
* Verwendung:
* php artisan payments:reminders
*
* Cron-Job Konfiguration (täglich um 9:00 Uhr):
* 0 9 * * * cd /path/to/project && php artisan payments:reminders >> /dev/null 2>&1
*
* Oder für stündliche Ausführung:
* 0 * * * * cd /path/to/project && php artisan payments:reminders >> /dev/null 2>&1
*
* Logs werden automatisch in storage/logs/laravel.log geschrieben
*/
class PaymentsReminders extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'payments:reminders';
protected $description = 'Run Payments Reminders';
private $timeStart;
private $dev = false;
private $paymentReminderService;
private $stats = [
'total_processed' => 0,
'reminders_sent' => 0,
'errors' => 0,
'skipped' => 0,
];
public function __construct(PaymentReminderService $paymentReminderService)
{
parent::__construct();
$this->paymentReminderService = $paymentReminderService;
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
\Log::info('Starting PaymentsReminders Command', ['timestamp' => now()]);
$this->info('RUN Command Payments Reminders: '.date('d.m.Y H:i'));
$this->timeStart = microtime(true);
try {
$this->functionReminder();
$executionTime = round(microtime(true) - $this->timeStart, 2);
$this->info("\n=== PAYMENT REMINDERS ABGESCHLOSSEN ===");
$this->info("Ausführungszeit: {$executionTime} Sekunden");
$this->info('Statistiken:');
$this->info(" - Gesamt verarbeitet: {$this->stats['total_processed']}");
$this->info(" - Erinnerungen gesendet: {$this->stats['reminders_sent']}");
$this->info(" - Fehler: {$this->stats['errors']}");
$this->info(" - Übersprungen: {$this->stats['skipped']}");
\Log::info('PaymentsReminders Command completed successfully', [
'execution_time' => $executionTime,
'stats' => $this->stats,
]);
return 0;
} catch (\Exception $e) {
\Log::error('PaymentsReminders Command failed', [
'error' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
$this->error('Command failed: '.$e->getMessage());
return 1;
}
}
/**
* Hauptfunktion für die Verarbeitung der Zahlungserinnerungen
*/
private function functionReminder()
{
$this->info('=== STARTE PAYMENT REMINDERS ===');
// Hole alle aktiven PaymentReminder und gruppiere sie nach clearingtype
$payment_reminders = PaymentReminder::where('active', true)->get();
$this->info('Gefundene aktive PaymentReminder: '.$payment_reminders->count());
if ($payment_reminders->isEmpty()) {
$this->warn('Keine aktiven PaymentReminder gefunden!');
return;
}
// Finde für jeden clearingtype das kleinste Intervall (in Tagen)
$intervals = $this->paymentReminderService->getActiveIntervals();
$this->info('Gefundene clearingtypes mit kleinsten Intervallen:');
foreach ($intervals as $clearingtype => $interval) {
$this->line(" - {$clearingtype}: {$interval} Tage");
}
// Verarbeite jeden clearingtype mit seinem kleinsten Intervall
foreach ($intervals as $clearingtype => $interval) {
$this->info("\n--- Verarbeite clearingtype: {$clearingtype} mit Intervall: {$interval} Tage ---");
$date = Carbon::now()->subDays($interval);
$this->line('Suche Zahlungen vor: '.$date->format('d.m.Y H:i:s'));
// Hole nur die neueste ShoppingPayment pro shopping_order_id
$shopping_payments = $this->paymentReminderService->getOpenPaymentsForClearingType($clearingtype, $interval);
$this->info("Gefundene offene Zahlungen für {$clearingtype}: ".$shopping_payments->count());
if ($shopping_payments->isEmpty()) {
$this->line("Keine Zahlungen für {$clearingtype} gefunden.");
continue;
}
// Verarbeite jede Zahlung
$this->line('--- START processPayment VERARBEITUNG');
foreach ($shopping_payments as $shopping_payment) {
$this->processPayment($shopping_payment, $clearingtype);
}
}
}
/**
* Verarbeitet eine einzelne Zahlung und sendet ggf. eine Erinnerung
*/
private function processPayment($shopping_payment, $clearingtype)
{
$this->stats['total_processed']++;
try {
$this->line("Verarbeite Order ID: {$shopping_payment->shopping_order_id}, Created: {$shopping_payment->created_at->format('d.m.Y H:i:s')}, Amount: {$shopping_payment->amount}, Reminder: {$shopping_payment->reminder}");
// Prüfe ob eine Erinnerung gesendet werden soll
if ($this->shouldSendReminder($shopping_payment, $clearingtype)) {
$this->sendReminderForPayment($shopping_payment);
} else {
$this->line('Übersprungen - Keine Erinnerung fällig');
$this->stats['skipped']++;
}
} catch (\Exception $e) {
$this->error("Fehler bei Order ID {$shopping_payment->shopping_order_id}: ".$e->getMessage());
$this->stats['errors']++;
\Log::error('Error processing payment reminder', [
'order_id' => $shopping_payment->shopping_order_id,
'payment_id' => $shopping_payment->id,
'error' => $e->getMessage(),
]);
}
}
/**
* Prüft ob eine Erinnerung für diese Zahlung gesendet werden soll
*
* Logik:
* - Erste Erinnerung: Nach X Tagen ab Bestelldatum
* - Weitere Erinnerungen: Nach Y Tagen ab letzter Erinnerung
*/
private function shouldSendReminder($shopping_payment, $clearingtype)
{
// Hole alle aktiven Erinnerungen für diesen Clearingtype
$payment_reminders = PaymentReminder::where('active', true)
->where('clearingtype', $clearingtype)
->orderBy('interval', 'asc') // von kein nach gross
->get();
if ($payment_reminders->isEmpty()) {
$this->line('shouldSendReminder - keine PaymentReminders');
return false;
}
// Wenn alle Erinnerungen bereits gesendet wurden
if ($shopping_payment->reminder >= $payment_reminders->count()) {
$this->line('shouldSendReminder - alle Erinnerungen wurden bereits gesendet');
return false;
}
$next_reminder = isset($payment_reminders[$shopping_payment->reminder]) ? $payment_reminders[$shopping_payment->reminder] : null;
if ($next_reminder == null) {
$next_reminder = isset($payment_reminders[0]) ? $payment_reminders[0] : null;
if ($next_reminder == null) {
$this->line('shouldSendReminder - keine Erinnerung gefunden');
return false;
}
}
$this->line("shouldSendReminder - nächste Erinnerung: {$next_reminder->interval} Tage");
// Wenn noch keine Erinnerung gesendet wurde, prüfe das erste Intervall
if ($shopping_payment->reminder == null || $shopping_payment->reminder == 0) {
$daysSinceOrder = $shopping_payment->created_at->diffInDays(now());
$this->line("shouldSendReminder - no reminder send first intervall - Tage seit Bestellung: {$daysSinceOrder} : Next intervall: {$next_reminder->interval}");
return $daysSinceOrder >= $next_reminder->interval;
}
// Hole die nächste Erinnerung
// Wenn bereits Erinnerungen gesendet wurden, prüfe das nächste Intervall
if ($shopping_payment->reminder_date) {
$current_reminder = $payment_reminders[$shopping_payment->reminder - 1];
$this->line("shouldSendReminder - letzte Erinnerung: {$current_reminder->interval} Tage");
$interval_difference = $next_reminder->interval - $current_reminder->interval;
$next_reminder_date = Carbon::parse($shopping_payment->reminder_date)->addDays($interval_difference);
$this->line("shouldSendReminder - next reminder date: {$next_reminder_date->format('d.m.Y H:i:s')}");
return now()->gte($next_reminder_date);
}
return false;
}
/**
* Sendet eine Erinnerung für eine spezifische Zahlung
*/
private function sendReminderForPayment($shopping_payment)
{
try {
$this->line('Sende Erinnerung...');
$result = $this->paymentReminderService->sendReminder($shopping_payment);
if ($result) {
$this->line('Erinnerung erfolgreich gesendet');
$this->stats['reminders_sent']++;
// Log für Cron-Job
\Log::info('Payment reminder sent via cron', [
'order_id' => $shopping_payment->shopping_order_id,
'payment_id' => $shopping_payment->id,
'reminder_count' => $shopping_payment->reminder + 1,
'email' => $shopping_payment->shopping_order->shopping_user->billing_email ?? 'N/A',
]);
} else {
$this->line('Keine Erinnerung gesendet (keine weitere Erinnerung verfügbar)');
$this->stats['skipped']++;
}
} catch (\Exception $e) {
$this->error('Fehler beim Senden der Erinnerung: '.$e->getMessage());
$this->stats['errors']++;
\Log::error('Error sending payment reminder', [
'order_id' => $shopping_payment->shopping_order_id,
'payment_id' => $shopping_payment->id,
'error' => $e->getMessage(),
]);
}
}
}

View file

@ -19,13 +19,27 @@ class Kernel extends ConsoleKernel
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
// $schedule->command('inspire')
// ->hourly();
if (config('app.debug') == false) {
$schedule->command('payments:accounts')
->sendOutputTo(storage_path('logs/cron.log'))
->appendOutputTo(storage_path('logs/cron-history.log'))
->emailOutputOnFailure(config('app.exception_mail'))
->onFailure(function () {
\Log::error('Payments:accounts command failed');
});
}
$schedule->command('payments:reminders')
->sendOutputTo(storage_path('logs/cron.log'))
->appendOutputTo(storage_path('logs/cron-reminders.log'))
->emailOutputOnFailure(config('app.exception_mail'))
->onFailure(function () {
\Log::error('Payments:reminders command failed');
});
}
/**

View file

@ -0,0 +1,158 @@
<?php
namespace App\Cron;
use App\Mail\MailCustomMessage;
use App\Mail\MailVerifyAccount;
use App\Models\UserHistory;
use App\Models\UserMessage;
use App\User;
use Carbon;
use Illuminate\Support\Facades\Mail;
class UserCheckPaymentsAccounts
{
/*RULES
reminders
> 29 renewal_days > set next_m_level to m_level
> 29 renewal_days $user->user_level->payment_year = 0 / false + 1 year
> 21 remind_first_days = reminder_first //status 31
> 14 remind_sec_days = reminder_sec //status 33
> 2 remind_last_days = reminder_last //status 34
> 0 deaktiv = reminder_deaktiv //status 35
*/
public static function userReminderPayments(User $user, $dev)
{
// 35 reminder_deaktiv
if (! $user->isActiveAccount()) { // payment_account gt now
return self::checkIsReminderSend($user, 35, $dev);
}
// 34 reminder_last
if ($user->daysActiveAccount() <= config('main.remind_last_days')) {
return self::checkIsReminderSend($user, 34, $dev);
}
// 33 reminder_sec
if ($user->daysActiveAccount() <= config('main.remind_sec_days')) {
return self::checkIsReminderSend($user, 33, $dev);
}
// 31 reminder_first
if ($user->daysActiveAccount() > config('main.remind_sec_days')) {
return self::checkIsReminderSend($user, 31, $dev);
}
return 0;
}
private static function checkIsReminderSend(User $user, $status, $dev)
{
$isSend = UserHistory::whereUserId($user->id)
->whereAction('reminder_payments')
->whereIdentifier($user->payment_account)
->whereStatus($status)
->get()->last();
if ($isSend) {
return 0;
}
if ($dev) {
$referenz = 0;
} else {
$referenz = self::sendReminderMail($user, $status);
}
UserHistory::create(['user_id' => $user->id, 'action' => 'reminder_payments', 'referenz' => $referenz, 'identifier' => $user->payment_account, 'status' => $status]);
return $status;
}
private static function sendReminderMail(User $user, $status)
{
$days = $user->daysActiveAccount();
if ($days < 0) {
$days = $days * -1;
}
$datetime = $user->getPaymentAccountDateFormat();
$pay_date = 0;
$price = 0;
/*$pay_date = Carbon::parse($user->payment_account)->modify('- '.config('main.abo_booking_days').' days')->format('d.m.Y');
$price = "";
if($user->payment_order_id && isset($user->payment_order_product->price)){
$price = 'von '.$user->payment_order_product->getFormattedPrice().' EUR';
}*/
$message = __('reminder.copy_first_'.$status, ['days' => $days, 'datetime' => $datetime, 'price' => $price, 'pay_date' => $pay_date]);
$message_last = __('reminder.copy_last_'.$status, ['days' => $days, 'datetime' => $datetime, 'price' => $price, 'pay_date' => $pay_date]);
$button = __('reminder.button_'.$status);
$message = preg_replace("/[\n\r]/", '', $message);
$message_last = preg_replace("/[\n\r]/", '', $message_last);
$data = [
'subject' => __('reminder.subject').' | ID: '.$status,
'message' => $message,
'message_last' => $message_last,
'url' => route('user_membership'),
'button' => $button,
];
// dump($data);
$sender = User::find(1);
$customer_mail = UserMessage::create([
'user_id' => $user->id,
'send_user_id' => $sender->id,
'email' => $user->email,
'subject' => $data['subject'],
'message' => $data['message'].' '.$data['message_last'],
]);
try {
if ($status >= 34) {
// Mail::to($user->email)->bcc(config('app.info_mail'))->send(new MailCustomMessage($user, $data, $sender, false));
} else {
// Mail::to($user->email)->send(new MailCustomMessage($user, $data, $sender, false));
}
} catch (\Exception $e) {
\Log::channel('cron')->error('Mail Error: '.$e->getMessage());
// Never reached
$customer_mail->fail = true;
$customer_mail->error = $e->getMessage();
$customer_mail->save();
return 0;
}
$customer_mail->send = true;
$customer_mail->sent_at = now();
$customer_mail->save();
return 1;
}
}
/*public function checkConfirmation()
{
User Register sind in der DB UserRegister, erst bei bestätigung wird es in die User DB übertragen
$now = date('Y-m-d H:i:s');
$next = date('Y-m-d H:i:s', strtotime('+3 week'));
$users = User::where('confirmed', '=', 0)->where('confirmation_code_to', '<', $now)->get();
foreach ($users as $user) {
//delete user
if ($user->confirmation_code_remider == 1) {
$this->userRepo->deleteUser($user);
}
//send new remider
if ($user->confirmation_code_remider == 0) {
Mail::to($user->email)->bcc(config('app.info_mail'))->send(new MailVerifyAccount($user->confirmation_code, $user));
$user->confirmation_code_to = $next;
$user->confirmation_code_remider = 1;
$user->save();
}
}
return "TOSK";
}*/

View file

@ -4,6 +4,9 @@ namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Throwable;
use Illuminate\Support\Facades\Mail;
use Symfony\Component\ErrorHandler\Exception\FlattenException;
use Symfony\Component\ErrorHandler\ErrorRenderer\HtmlErrorRenderer;
class Handler extends ExceptionHandler
{
@ -36,6 +39,9 @@ class Handler extends ExceptionHandler
*/
public function report(Throwable $exception)
{
if ($this->shouldReport($exception)) {
$this->sendEmail($exception);
}
parent::report($exception);
}
@ -52,4 +58,35 @@ class Handler extends ExceptionHandler
{
return parent::render($request, $exception);
}
public function sendEmail(Throwable $exception)
{
try {
$e = FlattenException::create($exception);
$handler = new HtmlErrorRenderer(true); // boolean, true raises debug flag...
$css = $handler->getStylesheet();
$content = $handler->getBody($e);
//Mail::to(config('app.exception_mail'))->send(new MailContact($contact));
// Verwende normale Mail-Klasse statt Facade, um Probleme bei der Initialisierung zu vermeiden
$to = config('app.exception_mail');
$subject = 'gruene-seele Exception: ' . \Request::fullUrl();
if ($to) {
\Mail::send('emails.exception', compact('css', 'content'), function ($message) use ($to, $subject) {
$message
->to($to)
->subject($subject)
;
});
}
} catch (Throwable $ex) {
// Einfache Fehlerprotokollierung ohne Facade
file_put_contents(
storage_path('logs/laravel-' . date('Y-m-d') . '.log'),
'[' . date('Y-m-d H:i:s') . '] exception-handler-error: ' . $ex->getMessage() . "\n",
FILE_APPEND
);
}
}
}

View file

@ -0,0 +1,33 @@
<?php
namespace App\Exports;
use Maatwebsite\Excel\Excel;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\Exportable;
use Maatwebsite\Excel\Concerns\WithHeadings;
class ExcelExport implements FromCollection, WithHeadings
{
protected $collection;
protected $headings;
use Exportable;
public function __construct($data,$header)
{
$this->collection = $data;
$this->headings = $header;
}
public function collection()
{
return collect($this->collection);
}
public function headings(): array
{
return [$this->headings];
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace App\Http\Controllers\Admin\Inventory;
use App\Http\Controllers\Controller;
use App\Http\Requests\Inventory\StoreLocationRequest;
use App\Http\Requests\Inventory\UpdateLocationRequest;
use App\Models\Location;
class LocationController extends Controller
{
public function index()
{
return view('admin.inventory.locations.index', [
'values' => Location::query()->orderBy('name')->get(),
]);
}
public function create()
{
return view('admin.inventory.locations.form', [
'model' => new Location(['active' => true]),
]);
}
public function store(StoreLocationRequest $request)
{
Location::create($request->validated());
\Session::flash('alert-save', '1');
return redirect()->route('admin.inventory.locations.index');
}
public function edit(Location $location)
{
return view('admin.inventory.locations.form', [
'model' => $location,
]);
}
public function update(UpdateLocationRequest $request, Location $location)
{
$location->update($request->validated());
\Session::flash('alert-save', '1');
return redirect()->route('admin.inventory.locations.index');
}
public function destroy(Location $location)
{
$location->delete();
\Session::flash('alert-success', __('Eintrag gelöscht'));
return redirect()->route('admin.inventory.locations.index');
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace App\Http\Controllers\Admin\Inventory;
use App\Http\Controllers\Controller;
use App\Http\Requests\Inventory\StoreMaterialQualityRequest;
use App\Http\Requests\Inventory\UpdateMaterialQualityRequest;
use App\Models\MaterialQuality;
class MaterialQualityController extends Controller
{
public function index()
{
return view('admin.inventory.material-qualities.index', [
'values' => MaterialQuality::query()->orderBy('pos')->orderBy('name')->get(),
]);
}
public function create()
{
return view('admin.inventory.material-qualities.form', [
'model' => new MaterialQuality(['pos' => 0]),
]);
}
public function store(StoreMaterialQualityRequest $request)
{
MaterialQuality::create($request->validated());
\Session::flash('alert-save', '1');
return redirect()->route('admin.inventory.material-qualities.index');
}
public function edit(MaterialQuality $materialQuality)
{
return view('admin.inventory.material-qualities.form', [
'model' => $materialQuality,
]);
}
public function update(UpdateMaterialQualityRequest $request, MaterialQuality $materialQuality)
{
$materialQuality->update($request->validated());
\Session::flash('alert-save', '1');
return redirect()->route('admin.inventory.material-qualities.index');
}
public function destroy(MaterialQuality $materialQuality)
{
$materialQuality->delete();
\Session::flash('alert-success', __('Eintrag gelöscht'));
return redirect()->route('admin.inventory.material-qualities.index');
}
}

View file

@ -0,0 +1,119 @@
<?php
namespace App\Http\Controllers\Admin\Inventory;
use App\Http\Controllers\Controller;
use App\Http\Requests\Inventory\StorePackagingItemRequest;
use App\Http\Requests\Inventory\UpdatePackagingItemRequest;
use App\Models\PackagingItem;
use App\Models\PackagingMaterial;
use App\Models\Supplier;
use App\Repositories\PackagingItemRepository;
use Illuminate\Http\Request;
class PackagingItemController extends Controller
{
public function __construct(
protected PackagingItemRepository $packagingItemRepository
) {}
public function index(Request $request)
{
$category = $request->get('category', 'packaging');
$isShipping = $category === 'shipping';
$query = PackagingItem::query()
->with(['packagingMaterial', 'supplier'])
->orderBy('name');
if ($isShipping) {
$query->where('category', 'shipping');
} else {
$query->where('category', 'packaging');
}
return view('admin.inventory.packaging-items.index', [
'values' => $query->get(),
'category' => $category,
'pageTitle' => $isShipping ? __('Versandverpackung') : __('Produktverpackung'),
]);
}
public function create(Request $request)
{
$category = $request->query('category', 'packaging');
if (! in_array($category, ['packaging', 'shipping'], true)) {
$category = 'packaging';
}
return view('admin.inventory.packaging-items.form', [
'model' => new PackagingItem(['active' => true, 'category' => $category === 'shipping' ? 'shipping' : 'packaging', 'weight_grams' => 0]),
'packagingMaterials' => PackagingMaterial::query()->orderBy('pos')->orderBy('name')->get(),
'suppliers' => Supplier::query()->orderBy('name')->get(),
'category' => $category,
]);
}
public function store(StorePackagingItemRequest $request)
{
$validated = $request->validated();
\Log::debug('PackagingItem STORE raw input', [
'category_raw' => $request->input('category'),
'category_hex' => bin2hex((string) $request->input('category')),
'all_input' => $request->all(),
]);
\Log::debug('PackagingItem STORE validated', $validated);
$item = $this->packagingItemRepository->create($validated);
\Session::flash('alert-save', '1');
$category = $item->category === 'shipping' ? 'shipping' : 'packaging';
return redirect()->route('admin.inventory.packaging-items.index', ['category' => $category]);
}
public function edit(PackagingItem $packagingItem)
{
$category = $packagingItem->category === 'shipping' ? 'shipping' : 'packaging';
return view('admin.inventory.packaging-items.form', [
'model' => $packagingItem,
'packagingMaterials' => PackagingMaterial::query()->orderBy('pos')->orderBy('name')->get(),
'suppliers' => Supplier::query()->orderBy('name')->get(),
'category' => $category,
]);
}
public function update(UpdatePackagingItemRequest $request, PackagingItem $packagingItem)
{
$validated = $request->validated();
\Log::debug('PackagingItem UPDATE raw input', [
'category_raw' => $request->input('category'),
'category_hex' => bin2hex((string) $request->input('category')),
'all_input' => $request->all(),
]);
\Log::debug('PackagingItem UPDATE validated', $validated);
$this->packagingItemRepository->update($packagingItem, $validated);
\Session::flash('alert-save', '1');
$category = $packagingItem->category === 'shipping' ? 'shipping' : 'packaging';
return redirect()->route('admin.inventory.packaging-items.index', ['category' => $category]);
}
public function destroy(PackagingItem $packagingItem)
{
$category = $packagingItem->category === 'shipping' ? 'shipping' : 'packaging';
$packagingItem->delete();
\Session::flash('alert-success', __('Eintrag gelöscht'));
return redirect()->route('admin.inventory.packaging-items.index', ['category' => $category]);
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace App\Http\Controllers\Admin\Inventory;
use App\Http\Controllers\Controller;
use App\Http\Requests\Inventory\StorePackagingMaterialRequest;
use App\Http\Requests\Inventory\UpdatePackagingMaterialRequest;
use App\Models\PackagingMaterial;
class PackagingMaterialController extends Controller
{
public function index()
{
return view('admin.inventory.packaging-materials.index', [
'values' => PackagingMaterial::query()->orderBy('pos')->orderBy('name')->get(),
]);
}
public function create()
{
return view('admin.inventory.packaging-materials.form', [
'model' => new PackagingMaterial(['pos' => 0]),
]);
}
public function store(StorePackagingMaterialRequest $request)
{
PackagingMaterial::create($request->validated());
\Session::flash('alert-save', '1');
return redirect()->route('admin.inventory.packaging-materials.index');
}
public function edit(PackagingMaterial $packagingMaterial)
{
return view('admin.inventory.packaging-materials.form', [
'model' => $packagingMaterial,
]);
}
public function update(UpdatePackagingMaterialRequest $request, PackagingMaterial $packagingMaterial)
{
$packagingMaterial->update($request->validated());
\Session::flash('alert-save', '1');
return redirect()->route('admin.inventory.packaging-materials.index');
}
public function destroy(PackagingMaterial $packagingMaterial)
{
$packagingMaterial->delete();
\Session::flash('alert-success', __('Eintrag gelöscht'));
return redirect()->route('admin.inventory.packaging-materials.index');
}
}

View file

@ -0,0 +1,169 @@
<?php
namespace App\Http\Controllers\Admin\Inventory;
use App\Http\Controllers\Controller;
use App\Http\Requests\Inventory\StoreProductionRequest;
use App\Models\Location;
use App\Models\Product;
use App\Models\Production;
use App\Repositories\ProductionRepository;
use App\Services\ProductionService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use Illuminate\View\View;
class ProductionController extends Controller
{
public function __construct(
protected ProductionRepository $productionRepository,
protected ProductionService $productionService
) {}
public function index(): View
{
return view('admin.inventory.productions.index', [
'values' => $this->productionRepository->listForIndex(),
]);
}
public function create(): View
{
$defaultLocationId = Location::query()->where('name', 'like', '%öln%')->value('id')
?? Location::query()->where('active', true)->first()?->id;
return view('admin.inventory.productions.create', [
'products' => Product::query()->where('active', 1)->orderBy('name')->get(['id', 'name']),
'locations' => Location::query()->where('active', true)->orderBy('name')->get(),
'defaultLocationId' => $defaultLocationId,
'model' => null,
]);
}
public function store(StoreProductionRequest $request): RedirectResponse
{
$payload = $request->validatedPayload();
try {
$production = $this->productionService->store(
[
'product_id' => $payload['product_id'],
'location_id' => $payload['location_id'],
'produced_at' => $payload['produced_at'],
'quantity' => $payload['quantity'],
'notes' => $payload['notes'],
],
$payload['ingredient_lines'],
(int) $request->user()->id
);
} catch (ValidationException $e) {
return redirect()->back()->withInput()->withErrors($e->errors());
}
if ($production->mhd_warning) {
\Session::flash('alert-warning', __('Hinweis: Mindestens eine Rohstoff-Charge hat ein kürzeres MHD als das geplante Produkt-MHD.'));
}
\Session::flash('alert-save', '1');
return redirect()->route('admin.inventory.productions.show', $production);
}
public function show(Production $production): View
{
$production->load([
'product',
'location',
'producedByUser.account',
'productionIngredients.ingredient',
'productionIngredients.stockEntry',
'productionPackagings.packagingItem.packagingMaterial',
]);
return view('admin.inventory.productions.show', [
'model' => $production,
]);
}
public function edit(Production $production): View
{
$production->load([
'product',
'location',
'productionIngredients.ingredient',
'productionIngredients.stockEntry',
]);
$defaultLocationId = $production->location_id;
return view('admin.inventory.productions.edit', [
'model' => $production,
'products' => Product::query()->where('active', 1)
->orWhere('id', $production->product_id)
->orderBy('name')->get(['id', 'name']),
'locations' => Location::query()->where('active', true)->orderBy('name')->get(),
'defaultLocationId' => $defaultLocationId,
]);
}
public function update(StoreProductionRequest $request, Production $production): RedirectResponse
{
$payload = $request->validatedPayload();
try {
$production = $this->productionService->updateProduction(
$production,
[
'product_id' => $payload['product_id'],
'location_id' => $payload['location_id'],
'produced_at' => $payload['produced_at'],
'quantity' => $payload['quantity'],
'notes' => $payload['notes'],
],
$payload['ingredient_lines'],
(int) $request->user()->id
);
} catch (ValidationException $e) {
return redirect()->back()->withInput()->withErrors($e->errors());
}
if ($production->mhd_warning) {
\Session::flash('alert-warning', __('Hinweis: Mindestens eine Rohstoff-Charge hat ein kürzeres MHD als das geplante Produkt-MHD.'));
}
\Session::flash('alert-save', '1');
return redirect()->route('admin.inventory.productions.show', $production);
}
public function copy(Production $production): View
{
$production->load([
'product',
'productionIngredients.ingredient',
'productionIngredients.stockEntry',
]);
$defaultLocationId = $production->location_id;
return view('admin.inventory.productions.create', [
'model' => $production,
'products' => Product::query()->where('active', 1)->orderBy('name')->get(['id', 'name']),
'locations' => Location::query()->where('active', true)->orderBy('name')->get(),
'defaultLocationId' => $defaultLocationId,
]);
}
public function recipeJson(Request $request, Product $product): JsonResponse
{
$locationId = (int) $request->query('location_id', 0);
$quantity = (int) $request->query('quantity', 1);
if ($locationId < 1) {
return response()->json(['message' => __('location_id erforderlich')], 422);
}
return response()->json(
$this->productionService->buildRecipePayload($product, $locationId, max(1, $quantity))
);
}
}

View file

@ -0,0 +1,233 @@
<?php
namespace App\Http\Controllers\Admin\Inventory;
use App\Http\Controllers\Controller;
use App\Http\Requests\Inventory\ReceiveStockEntryRequest;
use App\Http\Requests\Inventory\StoreStockEntryRequest;
use App\Http\Requests\Inventory\UpdateStockEntryRequest;
use App\Models\Ingredient;
use App\Models\Location;
use App\Models\MaterialQuality;
use App\Models\PackagingItem;
use App\Models\StockEntry;
use App\Models\Supplier;
use App\Repositories\StockEntryRepository;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
class StockEntryController extends Controller
{
public function __construct(
protected StockEntryRepository $stockEntryRepository
) {}
public function index(): View
{
return view('admin.inventory.stock-entries.index', array_merge($this->formSharedData(), [
'values' => $this->stockEntryRepository->listForIndex(),
]));
}
public function create(): View|RedirectResponse
{
if (! auth()->user()->isAdmin()) {
return redirect()->route('home');
}
return view('admin.inventory.stock-entries.create', array_merge($this->formSharedData(), [
'model' => new StockEntry([
'ordered_at' => now()->toDateString(),
'entry_type' => 'ingredient',
]),
]));
}
public function store(StoreStockEntryRequest $request): RedirectResponse
{
if (! $request->user()->isAdmin()) {
return redirect()->route('home');
}
$data = $request->validatedPayload();
$data['ordered_by'] = (int) auth()->id();
$this->stockEntryRepository->create($data);
\Session::flash('alert-save', '1');
return redirect()->route('admin.inventory.stock-entries.index');
}
public function show(StockEntry $stockEntry): View
{
$stockEntry->load([
'ingredient',
'packagingItem.packagingMaterial',
'supplier',
'location',
'quality',
'orderedByUser.account',
'receivedByUser.account',
]);
return view('admin.inventory.stock-entries.show', array_merge($this->formSharedData(), [
'model' => $stockEntry,
'materialQualities' => MaterialQuality::query()->orderBy('pos')->orderBy('name')->get(),
]));
}
public function edit(StockEntry $stockEntry): View|RedirectResponse
{
if (! auth()->user()->isAdmin()) {
return redirect()->route('home');
}
if (! $stockEntry->isPending()) {
\Session::flash('alert-error', __('Nur offene Bestellungen können bearbeitet werden.'));
return redirect()->route('admin.inventory.stock-entries.show', $stockEntry);
}
$stockEntry->load(['ingredient', 'packagingItem']);
return view('admin.inventory.stock-entries.edit', array_merge($this->formSharedData(), [
'model' => $stockEntry,
]));
}
public function update(UpdateStockEntryRequest $request, StockEntry $stockEntry): RedirectResponse
{
if (! $request->user()->isAdmin()) {
return redirect()->route('home');
}
if (! $stockEntry->isPending()) {
\Session::flash('alert-error', __('Nur offene Bestellungen können bearbeitet werden.'));
return redirect()->route('admin.inventory.stock-entries.show', $stockEntry);
}
$this->stockEntryRepository->update($stockEntry, $request->validatedPayload());
\Session::flash('alert-save', '1');
return redirect()->route('admin.inventory.stock-entries.index');
}
public function destroy(StockEntry $stockEntry): RedirectResponse
{
if (! auth()->user()->isAdmin()) {
return redirect()->route('home');
}
if (! $stockEntry->isPending()) {
\Session::flash('alert-error', __('Nur offene Bestellungen können gelöscht werden.'));
return redirect()->route('admin.inventory.stock-entries.index');
}
$stockEntry->delete();
\Session::flash('alert-success', __('Eintrag gelöscht'));
return redirect()->route('admin.inventory.stock-entries.index');
}
public function receive(ReceiveStockEntryRequest $request, StockEntry $stockEntry): RedirectResponse
{
if (! $stockEntry->isPending()) {
\Session::flash('alert-error', __('Eintrag nicht mehr offen.'));
return redirect()->route('admin.inventory.stock-entries.show', $stockEntry);
}
$data = $request->validated();
if ($stockEntry->entry_type !== 'ingredient') {
$data['quality_id'] = null;
$data['best_before'] = null;
}
$this->stockEntryRepository->receive($stockEntry, $data);
\Session::flash('alert-save', '1');
return redirect()->route('admin.inventory.stock-entries.show', $stockEntry->fresh());
}
public function searchIngredients(Request $request): JsonResponse
{
$term = trim((string) $request->query('q', ''));
if (mb_strlen($term) < 1) {
return response()->json(['results' => []]);
}
$rows = Ingredient::query()
->where('active', true)
->where(function ($query) use ($term) {
$query->where('name', 'like', '%'.$term.'%')
->orWhere('inci', 'like', '%'.$term.'%');
})
->orderBy('name')
->limit(30)
->get(['id', 'name', 'inci']);
$results = $rows->map(function (Ingredient $i) {
$text = $i->name;
if ($i->inci) {
$text .= ' ('.$i->inci.')';
}
return ['id' => $i->id, 'text' => $text];
})->values()->all();
return response()->json(['results' => $results]);
}
public function searchPackagingItems(Request $request): JsonResponse
{
$term = trim((string) $request->query('q', ''));
$entryType = $request->query('entry_type');
$categoryMap = [
'packaging' => 'packaging',
'shipping' => 'shipping',
];
$query = PackagingItem::query()
->where('active', true);
if ($entryType && isset($categoryMap[$entryType])) {
$query->where('category', $categoryMap[$entryType]);
}
if (mb_strlen($term) >= 1) {
$query->where('name', 'like', '%'.$term.'%');
}
$rows = $query->orderBy('name')->limit(30)->get(['id', 'name']);
$results = $rows->map(fn (PackagingItem $p) => [
'id' => $p->id,
'text' => $p->name,
])->values()->all();
return response()->json(['results' => $results]);
}
/**
* @return array<string, mixed>
*/
protected function formSharedData(): array
{
return [
'suppliers' => Supplier::query()->where('active', true)->orderBy('name')->get(),
'locations' => Location::query()->where('active', true)->orderBy('name')->get(),
'materialQualities' => MaterialQuality::query()->orderBy('pos')->orderBy('name')->get(),
'entryTypeLabels' => [
'ingredient' => __('Rohstoff'),
'packaging' => __('Produktverpackung'),
'shipping' => __('Versandverpackung'),
],
];
}
}

View file

@ -0,0 +1,59 @@
<?php
namespace App\Http\Controllers\Admin\Inventory;
use App\Http\Controllers\Controller;
use App\Http\Requests\Inventory\StoreSupplierCategoryRequest;
use App\Http\Requests\Inventory\UpdateSupplierCategoryRequest;
use App\Models\SupplierCategory;
class SupplierCategoryController extends Controller
{
public function index()
{
return view('admin.inventory.supplier-categories.index', [
'values' => SupplierCategory::query()->orderBy('pos')->orderBy('name')->get(),
]);
}
public function create()
{
return view('admin.inventory.supplier-categories.form', [
'model' => new SupplierCategory(['pos' => 0]),
]);
}
public function store(StoreSupplierCategoryRequest $request)
{
SupplierCategory::create($request->validated());
\Session::flash('alert-save', '1');
return redirect()->route('admin.inventory.supplier-categories.index');
}
public function edit(SupplierCategory $supplierCategory)
{
return view('admin.inventory.supplier-categories.form', [
'model' => $supplierCategory,
]);
}
public function update(UpdateSupplierCategoryRequest $request, SupplierCategory $supplierCategory)
{
$supplierCategory->update($request->validated());
\Session::flash('alert-save', '1');
return redirect()->route('admin.inventory.supplier-categories.index');
}
public function destroy(SupplierCategory $supplierCategory)
{
$supplierCategory->delete();
\Session::flash('alert-success', __('Eintrag gelöscht'));
return redirect()->route('admin.inventory.supplier-categories.index');
}
}

View file

@ -0,0 +1,74 @@
<?php
namespace App\Http\Controllers\Admin\Inventory;
use App\Http\Controllers\Controller;
use App\Http\Requests\Inventory\StoreSupplierRequest;
use App\Http\Requests\Inventory\UpdateSupplierRequest;
use App\Models\Country;
use App\Models\Supplier;
use App\Models\SupplierCategory;
use App\Repositories\SupplierRepository;
class SupplierController extends Controller
{
public function __construct(
protected SupplierRepository $supplierRepository
) {}
public function index()
{
return view('admin.inventory.suppliers.index', [
'values' => Supplier::query()->with(['country', 'supplierCategories'])->orderBy('name')->get(),
]);
}
public function create()
{
$defaultCountryId = Country::where('code', 'DE')->value('id');
return view('admin.inventory.suppliers.form', [
'model' => new Supplier(['active' => true, 'country_id' => $defaultCountryId]),
'countries' => Country::query()->orderBy('de')->get(),
'supplierCategories' => SupplierCategory::query()->orderBy('pos')->orderBy('name')->get(),
]);
}
public function store(StoreSupplierRequest $request)
{
$this->supplierRepository->create($request->validated());
\Session::flash('alert-save', '1');
return redirect()->route('admin.inventory.suppliers.index');
}
public function edit(Supplier $supplier)
{
$supplier->load('supplierCategories');
return view('admin.inventory.suppliers.form', [
'model' => $supplier,
'countries' => Country::query()->orderBy('de')->get(),
'supplierCategories' => SupplierCategory::query()->orderBy('pos')->orderBy('name')->get(),
]);
}
public function update(UpdateSupplierRequest $request, Supplier $supplier)
{
$this->supplierRepository->update($supplier, $request->validated());
\Session::flash('alert-save', '1');
return redirect()->route('admin.inventory.suppliers.index');
}
public function destroy(Supplier $supplier)
{
$supplier->delete();
\Session::flash('alert-success', __('Eintrag gelöscht'));
return redirect()->route('admin.inventory.suppliers.index');
}
}

View file

@ -0,0 +1,41 @@
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Services\PaymentReminderService;
use Illuminate\Http\Request;
class PaymentReminderController extends Controller
{
/* not used at the moment */
private $paymentReminderService;
public function __construct(PaymentReminderService $paymentReminderService)
{
$this->paymentReminderService = $paymentReminderService;
}
/**
* Zeige die Payment Reminders Übersicht
*/
public function index()
{
$detailedData = $this->paymentReminderService->getDetailedPaymentsData();
$summaryData = $this->paymentReminderService->getAllOpenPayments();
// Statistiken für die Übersicht
$totalPayments = collect($detailedData)->count();
$totalAmount = collect($detailedData)->sum('amount');
$clearingTypes = collect($detailedData)->groupBy('clearingtype')->map->count();
return view('admin.payment.reminder.index', compact(
'detailedData',
'summaryData',
'totalPayments',
'totalAmount',
'clearingTypes'
));
}
}

View file

@ -20,6 +20,11 @@ class AuthController extends Controller
public $successStatus = 200;
public function test(Request $request)
{
var_dump("testing");
die("test");
}
public function login(Request $request)
{

View file

@ -265,7 +265,7 @@ class ShoppingUserController extends Controller
$shopping_user = ShoppingUser::create($data);
//Kundenhoheit prüfen
$priority = CustomerPriority::checkOne($shopping_user, true, false);
$priority = CustomerPriority::checkOne($shopping_user, true, false, true);
\App\Services\Shop::newUserOrder($shopping_user->number);
//exists //like //update
$user = $this->prepareForShow($shopping_user);
@ -595,7 +595,9 @@ class ShoppingUserController extends Controller
if ($order->price != ($product->price * 100)) {
$error[] = "different price: " . ($product->price * 100);
}
Yard::instance('shopping')->add($product->id, $product->name, (int) $order->qty, $product->price, ['image' => [], 'slug' => $product->slug, 'weight' => $product->weight]);
Yard::instance('shopping')->add($product->id, $product->name, (int) $order->qty, $product->price, $product->tax, ['image' => [], 'slug' => $product->slug, 'weight' => $product->weight]);
}
}
$order->message = $error;
@ -604,7 +606,7 @@ class ShoppingUserController extends Controller
$ShippingCountry = ShippingCountry::whereCountryId($shopping_user->shipping_country_id)->first();
if($ShippingCountry){
Yard::instance('shopping')->setShippingCountryWithPrice($ShippingCountry->id);
Yard::instance('shopping')->setShippingCountryWithPrice($ShippingCountry->id, 'ot');
}
$shopping_order = $this->makeShoppingOrder($shopping_user, $wp_invoice_path, $wp_notice);
$this->orderStatusSendMail($shopping_order);

View file

@ -3,9 +3,10 @@
namespace App\Http\Controllers;
use App\Models\Attribute;
use App\Models\ProductAttribute;
use Request;
use App\Models\Attribute;
use App\Models\AttributeType;
use App\Models\ProductAttribute;
class AttributeController extends Controller
@ -13,40 +14,71 @@ class AttributeController extends Controller
public function __construct()
{
$this->middleware('admin');
$this->middleware('copyreader');
}
public function index()
{
$data = [
'values' => Attribute::all(),
'attribute_types' => AttributeType::all(),
'attributes' => Attribute::all(),
'trans' => array_keys(config('localization.supportedLocales')),
];
return view('admin.attribute.index', $data);
}
public function store()
{
$data = Request::all();
if($data['id'] == "new"){
$model = Attribute::create([
'parent_id' => null,
'name' => $data['name'],
'pos' => $data['pos'],
'active' => isset($data['active']) ? true : false,
]);
}else{
$model = Attribute::find($data['id']);
$model->parent_id = null;
$model->name = $data['name'];
$model->pos = $data['pos'];
$model->active = isset($data['active']) ? true : false;
$model->save();
if(isset($data['action'])){
if( $data['action'] === "attribute-type"){
if($data['id'] == "new"){
$model = AttributeType::create([
'parent_id' => null,
'name' => $data['name'],
'description' => $data['description'],
'pos' => $data['pos'],
'active' => isset($data['active']) ? true : false,
]);
}else{
$model = AttributeType::find($data['id']);
$model->parent_id = null;
$model->name = $data['name'];
$model->description = $data['description'];
$model->pos = $data['pos'];
$model->active = isset($data['active']) ? true : false;
$model->save();
}
}
if($data['action'] === "attribute"){
if($data['id'] == "new"){
$model = Attribute::create([
'parent_id' => null,
'attribute_type_id' => $data['attribute_type_id'],
'name' => $data['name'],
'value' => $data['value'],
'pos' => $data['pos'],
'active' => isset($data['active']) ? true : false,
]);
}else{
$model = Attribute::find($data['id']);
$model->parent_id = null;
$model->name = $data['name'];
$model->value = $data['value'];
$model->attribute_type_id = $data['attribute_type_id'];
$model->pos = $data['pos'];
$model->active = isset($data['active']) ? true : false;
$model->save();
}
}
}
if(!empty($data['trans'])){
/*if(!empty($data['trans'])){
$trans = [];
foreach ($data['trans'] as $lang => $value){
if($value && $value != null){
@ -57,7 +89,7 @@ class AttributeController extends Controller
$model->trans_name = $trans;
$model->save();
}
}
}*/
\Session()->flash('alert-save', '1');
return redirect(route('admin_product_attributes'));
@ -66,21 +98,41 @@ class AttributeController extends Controller
}
public function delete($id){
public function delete($attr, $id){
if(ProductAttribute::where('attribute_id', $id)->count()){
\Session()->flash('alert-error', 'Eintrag wird als Produktattribute verwendet');
if($attr === 'type'){
if(Attribute::where('attribute_type_id', $id)->count()){
\Session()->flash('alert-error', 'Attribute Type wird bei den Attributen verwendet');
return redirect(route('admin_product_attributes'));
}
/* if(AttributeType::where('parent_id', $id)->count()){
\Session()->flash('alert-error', 'Eintrag wird als Main Attribute verwendet');
return redirect(route('admin_product_attributes'));
}
*/
$model = AttributeType::findOrFail($id);
$model->delete();
\Session()->flash('alert-success', 'Attribute Type gelöscht');
return redirect(route('admin_product_attributes'));
}
/* if(Attribute::where('parent_id', $id)->count()){
\Session()->flash('alert-error', 'Eintrag wird als Main Attribute verwendet');
return redirect(route('admin_industry_sectors'));
if($attr === 'attr'){
if(ProductAttribute::where('attribute_id', $id)->count()){
\Session()->flash('alert-error', 'Attribute wird bei den Produkten verwendet');
return redirect(route('admin_product_attributes'));
}
/* if(Attribute::where('parent_id', $id)->count()){
\Session()->flash('alert-error', 'Eintrag wird als Main Attribute verwendet');
return redirect(route('admin_product_attributes'));
}
*/
$model = Attribute::findOrFail($id);
$model->delete();
\Session()->flash('alert-success', 'Eintrag gelöscht');
return redirect(route('admin_product_attributes'));
}
*/
$model = Attribute::findOrFail($id);
$model->delete();
\Session()->flash('alert-success', 'Eintrag gelöscht');
return redirect(route('admin_product_attributes'));
}
}

View file

@ -5,7 +5,7 @@ namespace App\Http\Controllers;
use App\Models\Category;
use App\Models\IqImage;
use App\Models\ProductCategory;
use\Request;
use Request;
class CategoryController extends Controller
@ -14,14 +14,14 @@ class CategoryController extends Controller
public function __construct()
{
$this->middleware('admin');
$this->middleware('copyreader');
}
public function index()
{
$data = [
'values' => Category::all(),
'values' => Category::orderBy('pos', 'ASC')->get(),
];
return view('admin.category.index', $data);
}
@ -46,42 +46,66 @@ class CategoryController extends Controller
{
$data = Request::all();
$data['active'] = isset($data['active']) ? true : false;
$data['parent_id'] = isset($data['parent_id']) ? $data['parent_id'] : null;
if($data['id'] == "new"){
$model = Category::create($data);
}else{
$model = Category::find($data['id']);
$model->fill($data)->save();
if($data['action'] === 'save-product_category'){
if($data['id'] === 'new'){
$ProductCategory = ProductCategory::create([
'pos' => $data['pos'],
'product_id' => $data['product_id'],
'category_id' => $data['category_id'],
]);
\Session()->flash('alert-save', '1');
return redirect(route('admin_product_category_edit', [$ProductCategory->category_id]));
}else{
$ProductCategory = ProductCategory::findOrFail($data['id']);
if($ProductCategory->category_id != $data['category_id']){
abort(404);
}
$ProductCategory->pos = $data['pos'];
$ProductCategory->product_id = $data['product_id'];
$ProductCategory->save();
\Session()->flash('alert-save', '1');
return redirect(route('admin_product_category_edit', [$ProductCategory->category_id]));
}
}
$trans = [];
if(!empty($data['trans_name'])){
if($data['action'] === 'save-form'){
$data['active'] = isset($data['active']) ? true : false;
$data['parent_id'] = isset($data['parent_id']) ? $data['parent_id'] : null;
if($data['id'] == "new"){
$model = Category::create($data);
}else{
$model = Category::find($data['id']);
$model->fill($data)->save();
}
foreach ($data['trans_name'] as $lang => $value){
if($value && $value != null){
$trans[$lang] = $value;
$trans = [];
if(!empty($data['trans_name'])){
foreach ($data['trans_name'] as $lang => $value){
if($value && $value != null){
$trans[$lang] = $value;
}
}
}
}
$model->trans_name = $trans;
$model->save();
$model->trans_name = $trans;
$model->save();
$trans = [];
if(!empty($data['trans_headline'])){
foreach ($data['trans_headline'] as $lang => $value){
if($value && $value != null){
$trans[$lang] = $value;
$trans = [];
if(!empty($data['trans_headline'])){
foreach ($data['trans_headline'] as $lang => $value){
if($value && $value != null){
$trans[$lang] = $value;
}
}
}
$model->trans_headline = $trans;
$model->save();
\Session()->flash('alert-save', '1');
return redirect(route('admin_product_categories'));
}
$model->trans_headline = $trans;
$model->save();
\Session()->flash('alert-save', '1');
return redirect(route('admin_product_categories'));
}
@ -157,7 +181,7 @@ class CategoryController extends Controller
return redirect(route('admin_product_category_edit', [$category->id]));
}
catch (Exception $e) {
catch (\Exception $e) {
\Session()->flash('alert-danger', "Fehler".$e);
return redirect(route('admin_product_category_edit', [$category->id]));
}

View file

@ -52,6 +52,8 @@ class CountryController extends Controller
$data['active'] = isset($data['active']) ? true : false;
$data['switch'] = isset($data['switch']) ? true : false;
$data['translate'] = isset($data['translate']) ? true : false;
$data['eu_country'] = isset($data['eu_country']) ? true : false;
$data['own_eur'] = isset($data['own_eur']) ? true : false;
$data['currency'] = isset($data['currency']) ? true : false;
$data['currency_faktor'] = $data['currency_faktor'] == "" ? null : reFormatNumber($data['currency_faktor']);

View file

@ -43,6 +43,7 @@ class CronController extends Controller
if($key !== 'key'){
abort(404);
}
die('not in use');
if($action === 'check_payments_account'){
$this->checkPaymentsAccounts();
}
@ -54,6 +55,8 @@ class CronController extends Controller
*/
public function checkConfirmation()
{
/*
User Register sind in der DB UserRegister, erst bei bestätigung wird es in die User DB übertragen
$now = date('Y-m-d H:i:s');
$next = date('Y-m-d H:i:s', strtotime('+3 week'));
@ -68,12 +71,12 @@ class CronController extends Controller
}
//send new remider
if ($user->confirmation_code_remider == 0) {
Mail::to($user->email)->send(new MailVerifyAccount($user->confirmation_code, $user));
Mail::to($user->email)->bcc(config('app.info_mail'))->send(new MailVerifyAccount($user->confirmation_code, $user));
$user->confirmation_code_to = $next;
$user->confirmation_code_remider = 1;
$user->save();
}
}
}*/
return "TOSK";
}
@ -218,7 +221,7 @@ class CronController extends Controller
]);
try{
if($status >= 34){
Mail::to($user->email)->bcc(config('app.default_mail'))->send(new MailCustomMessage($user, $data, $sender, false));
Mail::to($user->email)->bcc(config('app.info_mail'))->send(new MailCustomMessage($user, $data, $sender, false));
}else{
Mail::to($user->email)->send(new MailCustomMessage($user, $data, $sender, false));
}

View file

@ -15,7 +15,7 @@ class DataTableController extends Controller
public function getUsers()
{
$query = User::with('account')->select('users.*')->where('users.deleted_at', '=', null)->where('users.admin', "<", 4);
$query = User::with('account')->select('users.*')->where('users.deleted_at', '=', null)->where('users.admin', "<", 10);
return \DataTables::eloquent($query)
->addColumn('first_name', function (User $user) {
@ -30,6 +30,9 @@ class DataTableController extends Controller
->addColumn('admin', function (User $user) {
return '<a href="#" data-toggle="modal" data-target="#modals-admin" data-id="'.$user->id.'" data-email="'.$user->email.'" data-admin="'.$user->admin.'">'.HTMLHelper::getRoleLabel($user->admin).'</a>';
})
->addColumn('role', function (User $user) {
return $user->user_level ? $user->user_level->name : '';
})
->addColumn('confirmed', function (User $user) {
$date = $user->getConfirmationDateFormat();
$link = '<a href="#" data-toggle="modal" data-target="#modals-confirmed" data-id="'.$user->id.'" data-email="'.$user->email.'" data-confirmed="'.$user->confirmed.'" data-confirmation_date="'.$date.'">';
@ -71,6 +74,9 @@ class DataTableController extends Controller
}
return "-";
})*/
->addColumn('country', function (User $user) {
return ($user->account && $user->account->country) ? $user->account->country->de : '';
})
->addColumn('my_payment_methods', function (User $user) {
$payment_methods = json_encode($user->payment_methods);
$link = '<a href="#" data-toggle="modal" data-target="#modals-payment_methods" data-id="'.$user->id.'" data-email="'.$user->email.'" data-payment_methods="'.htmlspecialchars($payment_methods).'">';

View file

@ -2,11 +2,15 @@
namespace App\Http\Controllers;
use Storage;
use Response;
use App\Models\File;
use App\Models\ShoppingOrder;
use App\Models\UserCredit;
use App\Services\Credit;
use App\Services\Invoice;
use App\Services\PDFMerger;
use Auth;
use Response;
use Storage;
class FileController extends Controller
{
@ -15,26 +19,25 @@ class FileController extends Controller
*
* @return void
*/
public function __construct()
public function __construct() {}
private function isPermission($user_id)
{
}
private function isPermission($user_id){
if(Auth::user()->isAdmin() || $user_id == Auth::user()->id){
if (Auth::user()->isAdmin() || $user_id == Auth::user()->id) {
return true;
}
abort(404);
abort(404);
}
public function show($id = null, $disk = null, $do='file')
public function show($id = null, $disk = null, $do = 'file')
{
$path = "";
$filename = "";
$path = '';
$filename = '';
if($disk === 'user'){
$file = \App\Models\File::findOrFail($id);
if ($disk === 'user') {
$file = File::findOrFail($id);
$this->isPermission($file->user_id);
$path = Storage::disk($disk)->path($file->dir.$file->filename);
if (file_exists($path)) {
@ -42,66 +45,100 @@ class FileController extends Controller
}
}
if ($disk === 'invoice'){
$shopping_order = \App\Models\ShoppingOrder::findOrFail($id);
if ($disk === 'invoice') {
$shopping_order = ShoppingOrder::findOrFail($id);
$this->isPermission($shopping_order->auth_user_id);
$filename = Invoice::getFilename($shopping_order);
$path = Invoice::getDownloadPath($shopping_order);
if (!Storage::disk('public')->exists($path)) {
return Response::make('File no found.', 404);
}
$file = Storage::disk('public')->get($path);
$type = Storage::disk('public')->mimeType($path);
if($do === 'download'){
return Response::make($file, 200)
->header("Content-Type", $type)
->header('Content-disposition', 'attachment; filename="'.$filename.'"');
/* $full_path = Invoice::getDownloadPath($shopping_order, true);
$he
if (file_exists($full_path)) {
return Response::download($full_path, $filename);
}*/
}
if($do === 'stream'){
return Response::make($file, 200)
->header("Content-Type", $type)
->header('Content-disposition','filename="'.$filename.'"');
}
}
if ($disk === 'credit'){
$UserCredit = \App\Models\UserCredit::findOrFail($id);
$this->isPermission($UserCredit->auth_user_id);
if ($disk === 'delivery') {
$shopping_order = ShoppingOrder::findOrFail($id);
$this->isPermission($shopping_order->auth_user_id);
$filename = Invoice::getDeliveryFilename($shopping_order);
$path = Invoice::getDownloadPathDelivery($shopping_order);
}
if ($disk === 'cancellation') {
$shopping_order = ShoppingOrder::findOrFail($id);
$this->isPermission($shopping_order->auth_user_id);
$filename = Invoice::getCancellationFilename($shopping_order);
$path = Invoice::getCancellationDownloadPath($shopping_order);
}
if ($disk === 'invoice_delivery') {
$shopping_order = ShoppingOrder::findOrFail($id);
$this->isPermission($shopping_order->auth_user_id);
$ifilename = Invoice::getFilename($shopping_order);
$ipath = Invoice::getDownloadPath($shopping_order, true);
$dfilename = Invoice::getDeliveryFilename($shopping_order);
$dpath = Invoice::getDownloadPathDelivery($shopping_order, true);
$oMerger = new PDFMerger;
$oMerger->init();
$oMerger->addPDF($ipath);
$oMerger->addPDF($dpath);
$filename = str_replace('Rechnung-', 'Rechnung-Lieferschein-', $ifilename);
$oMerger->setFileName($filename);
$oMerger->merge();
$file = $oMerger->output();
return Response::make($file, 200)
->header('Content-Type', 'application/pdf')
->header('Content-disposition', 'attachment; filename="'.$filename.'"');
}
if ($disk === 'credit') {
$UserCredit = UserCredit::findOrFail($id);
$this->isPermission($UserCredit->auth_user_id);
$filename = Credit::getFilename($UserCredit);
$path = Credit::getDownloadPath($UserCredit);
}
if (!Storage::disk('public')->exists($path)) {
return Response::make('File no found.', 404);
}
$file = Storage::disk('public')->get($path);
$type = Storage::disk('public')->mimeType($path);
if (! Storage::disk('public')->exists($path)) {
return Response::make('File no found.', 404);
}
if($do === 'download'){
return Response::make($file, 200)
->header("Content-Type", $type)
->header('Content-disposition', 'attachment; filename="'.$filename.'"');
/* $full_path = Invoice::getDownloadPath($shopping_order, true);
$he
if (file_exists($full_path)) {
return Response::download($full_path, $filename);
}*/
}
if($do === 'stream'){
return Response::make($file, 200)
->header("Content-Type", $type)
->header('Content-disposition','filename="'.$filename.'"');
}
$file = Storage::disk('public')->get($path);
$mime = Storage::disk('public')->mimeType($path);
if ($do === 'download') {
return Response::make($file, 200)
->header('Content-Type', $mime)
->header('Content-disposition', 'attachment; filename="'.$filename.'"');
/* $full_path = Invoice::getDownloadPath($shopping_order, true);
$he
if (file_exists($full_path)) {
return Response::download($full_path, $filename);
}*/
}
if ($do === 'stream') {
return Response::make($file, 200)
->header('Content-Type', $mime)
->header('Content-disposition', 'filename="'.$filename.'"');
}
if ($do === 'file') {
return Response::make($file, 200)
->header('Content-Type', $mime)
->header('Content-disposition', 'filename="'.$filename.'"');
}
if ($do === 'image') {
return Response::make($file, 200)
->header('Content-Type', $mime);
}
if ($do === 'pdf') {
$path = storage_path().'/app/public/'.$path;
$headers = [
'Content-Type:'.$mime,
// 'Content-Length: ' . $file->size
// 'Content-Disposition: ' . $stream . '; filename=' . $file->original_name
];
return Response::download($path, $filename, $headers);
}
}
}

View file

@ -90,34 +90,7 @@ class HomeController extends Controller
}
public function verify($confirmation_code){
if( ! $confirmation_code)
{
return redirect('/status/error');
}
$user = User::whereConfirmationCode($confirmation_code)->first();
if ( ! $user)
{
return redirect('/status/not/found');
}
if($user->confirmed === 0){
$user->confirmed = 1;
//kill after wizzard!
// $user->confirmation_code = null;
// $user->confirmation_code_to = null;
// $user->confirmation_code_remider = 0;
$user->confirmation_date = now();
}
$user->save();
//Login!
Auth::login($user);
return redirect('/home');
}
public function statusRegister(){
return view('status.status_register');

View file

@ -84,6 +84,7 @@ class ImportProductController extends Controller
ProductImage::create([
'product_id' => $product->id,
'type' => 'product', // 'product',
'filename' => $name,
'original_name' => $original_name,
'ext' => $ext,

View file

@ -2,21 +2,15 @@
namespace App\Http\Controllers;
use App\Models\Category;
use App\Models\Ingredient;
use App\Models\IqImage;
use App\Models\ProductCategory;
use App\Models\ProductIngredient;
use Request;
class IngredientController extends Controller
{
public function __construct()
{
$this->middleware('admin');
$this->middleware('copyreader');
}
public function index()
@ -25,22 +19,24 @@ class IngredientController extends Controller
$data = [
'values' => Ingredient::all(),
];
return view('admin.ingredient.index', $data);
}
public function edit($id)
{
if($id === "new"){
$model = new Ingredient();
if ($id === 'new') {
$model = new Ingredient;
$model->active = true;
}else{
} else {
$model = Ingredient::findOrFail($id);
}
$data = [
'model' => $model,
//'trans' => array_keys(config('localization.supportedLocales')),
// 'trans' => array_keys(config('localization.supportedLocales')),
];
return view('admin.ingredient.edit', $data);
}
@ -49,30 +45,42 @@ class IngredientController extends Controller
$data = Request::all();
$data['active'] = isset($data['active']) ? true : false;
if($data['id'] === "new"){
if (isset($data['default_factor']) && $data['default_factor'] !== '') {
$data['default_factor'] = reFormatNumber($data['default_factor']) ?: 1.10;
}
if (isset($data['min_stock_alert']) && $data['min_stock_alert'] === '') {
$data['min_stock_alert'] = null;
} elseif (isset($data['min_stock_alert']) && $data['min_stock_alert'] !== null) {
$data['min_stock_alert'] = reFormatNumber($data['min_stock_alert']);
}
if (empty($data['material_quality_id'])) {
$data['material_quality_id'] = null;
}
if ($data['id'] === 'new') {
$model = Ingredient::create($data);
}else{
} else {
$model = Ingredient::find($data['id']);
$model->fill($data)->save();
}
\Session()->flash('alert-save', '1');
return redirect(route('admin_product_ingredients'));
return redirect(route('admin_product_ingredients'));
}
public function delete($id){
public function delete($id)
{
if(ProductIngredient::where('ingredient_id', $id)->count()) {
if (ProductIngredient::where('ingredient_id', $id)->count()) {
\Session()->flash('alert-error', 'Eintrag wird als Produkt-Inhaltsstoff verwendet');
return redirect(route('admin_product_ingredients'));
}
$model = Ingredient::findOrFail($id);
$model->delete();
\Session()->flash('alert-success', 'Eintrag gelöscht');
return redirect(route('admin_product_ingredients'));
}
}

View file

@ -2,20 +2,23 @@
namespace App\Http\Controllers;
use App\Exports\ExcelExport;
use Request;
use App\User;
use Validator;
use App\Services\SysLog;
use App\Models\UserAccount;
use App\Models\UserHistory;
use Maatwebsite\Excel\Facades\Excel;
use App\Services\UserService;
use App\Mail\MailAccountActive;
use App\Mail\MailCustomMessage;
use App\Mail\MailVerifyAccount;
use App\Mail\MailVerifyContact;
use App\Mail\MailAccountActive;
use App\Models\UserAccount;
use App\Models\UserHistory;
use App\Repositories\ContractPDFRepository;
use App\Models\UserWhitelabelProduct;
use App\Repositories\UserRepository;
use App\Services\SysLog;
use App\Services\UserService;
use App\User;
use Illuminate\Support\Facades\Mail;
use Request;
use Validator;
use App\Repositories\ContractPDFRepository;
class LeadController extends Controller
{
@ -33,13 +36,14 @@ class LeadController extends Controller
*/
public function index()
{
$this->setFilterVars();
$data = [
'values' => User::where('admin', '=', 0)->where('confirmation_code_remider', '!=', 2)->get(),
];
return view('admin.lead.index', $data);
}
/**
* @param $id
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
@ -122,7 +126,17 @@ class LeadController extends Controller
$data = Request::all();
$show = Request::get('show');
dd($data);
if(isset($data['action']) && $data['action'] == "reverse_charge_validate" && isset($data['user_id'])){
$user = User::findOrFail($data['user_id']);
return $this->userRepo->reverse_charge_validate($data, $user, route('admin_lead_edit', [$user->id]));
}
if(isset($data['action']) && $data['action'] == "reverse_charge_delete" && isset($data['user_id'])){
$user = User::findOrFail($data['user_id']);
return $this->userRepo->reverse_charge_delete($data, $user, route('admin_lead_edit', [$user->id]));
}
if ($data['user_id'] === "new" || $data['user_id'] == 0) {
$rules = array(
'salutation' => 'required',
@ -188,6 +202,7 @@ class LeadController extends Controller
if(isset($data['m_data_edit']) && $data['m_data_edit'] === "TSOK"){
$user = $this->userRepo->getModel();
$user->m_level = isset($data['m_level']) ? $data['m_level'] : NULL;
$user->lead_type_id = isset($data['lead_type_id']) ? $data['lead_type_id'] : NULL;
$user->m_sponsor = isset($data['m_sponsor']) ? $data['m_sponsor'] : NULL;
$user->save();
}
@ -203,7 +218,7 @@ class LeadController extends Controller
//10 == start wizard form create Lead
$user->wizard = 10;
$user->save();
Mail::to($user->email)->send(new MailVerifyContact($confirmation_code, $user));
Mail::to($user->email)->bcc(config('app.info_mail'))->send(new MailVerifyContact($confirmation_code, $user));
\Session()->flash('alert-save', true);
return redirect(route('admin_leads'));
@ -216,146 +231,142 @@ class LeadController extends Controller
}
//user released when register is complete
public function released($action, $id){
$user = User::findOrFail($id);
if($action === 'completed'){
$validator = Validator::make(Request::all(), []);
/*if(!$user->m_sponsor){
$validator->errors()->add('m_sponsor', __('Vertriebspartner hat keinen Sponsor.'));
}*/
if(!$user->account->m_first_name){
$validator->errors()->add('m_first_name', __('Vertriebspartner hat keinen Vornamen.'));
}
if(!$user->account->m_last_name){
$validator->errors()->add('m_last_name', __('Vertriebspartner hat keinen Nachnamen.'));
}
if ($validator->errors()->count()) {
return back()->withErrors($validator)->withRequest(Request::all());
}
if(!$user->account->m_account){
$user->account->m_account = UserAccount::withTrashed()->max('m_account') +1;
$user->account->save();
}
//create PDF
$pdf = new ContractPDFRepository($user);
$pdf->_set('disk', 'user');
$pdf->_set('dir', '/'.$user->id.'/documents/');
$pdf->_set('user_id', $user->id);
$pdf->_set('identifier', 'contract');
$pdf->createContractPDF();
//set wizard tp payments
$user->wizard = 20;
$user->active = 1;
$user->active_date = now();
$user->confirmation_code = null;
$user->confirmation_code_to = null;
$user->confirmation_code_remider = 0;
$user->save();
//mail with code to user?
try {
Mail::to($user->email)->send(new MailAccountActive($user));
}
catch(\Exception $e){
SysLog::action('released', 'admin_lead', 5)
->setUserId($user->id)
->setModel($user->id, User::class)
->setMessage('Error send released E-Mail: '.$e->getMessage())
->save();
}
UserHistory::create(['user_id' => $user->id, 'action'=>'released_completed', 'status'=>0]);
\Session()->flash('alert-success', "Vertriebspartner freigeschaltet!");
public function update()
{
$data = Request::all();
$show = Request::get('show');
if(!isset($data['user_id']) || $data['user_id'] === "new" || $data['user_id'] == 0){
abort(404, 'User not found');
}
$user = User::findOrFail($data['user_id']);
if($action === 'incomplete'){
if(isset($data['action'])){
//reset release
$confirmation_code = UserService::createConfirmationCode();
$user->confirmation_code = $confirmation_code;
$user->confirmation_code_to = date('Y-m-d H:i:s', strtotime('+1 week'));
$user->confirmation_code_remider = 0;
$user->wizard = 1;
$user->release_account = null;
$user->save();
$input = Request::all();
$data = [
'subject' => $input['account_incomplete_subject'],
'message' => $input['account_incomplete_message'],
'confirmation_code' => $confirmation_code,
];
try {
Mail::to($user->email)->send(new MailCustomMessage($user, $data, \Auth::user(), true));
//add whitelabel products
if($data['action'] === 'add_whitelabel_products'){
if(isset($data['whitelabel_products']) && is_array($data['whitelabel_products'])){
foreach ($data['whitelabel_products'] as $product_id){
$user->whitelabel_products()->create(['product_id' => $product_id]);
}
}
\Session()->flash('alert-save', true);
}
catch(\Exception $e){
SysLog::action('released_incomplete', 'admin_lead', 5)
->setUserId($user->id)
->setModel($user->id, User::class)
->setMessage('Error send released_incomplete E-Mail: '.$e->getMessage())
->save();
//remove whitelabel products
if($data['action'] === 'remove_whitelabel_products'){
if(isset($data['whitelabel_products']) && is_array($data['whitelabel_products'])){
$user->whitelabel_products()->whereIn('product_id', $data['whitelabel_products'])->delete();
}
\Session()->flash('alert-success', "Produkt gelöscht");
}
if($data['action'] === 'upload_white_label_image'){
//id == user_whitelabel_product_id
$whitelabel_product = UserWhitelabelProduct::findOrFail($data['id']);
if($whitelabel_product && $user->id == $whitelabel_product->user_id){
return \App\Services\ProductImage::imageUpload('user_wl_product', $whitelabel_product, Request::get('upload_type'));
}
}
//update whitelabel products
if($data['action'] === 'update_whitelabel_products'){
if(isset($data['image_wl_attributes']) && is_array($data['image_wl_attributes'])){
foreach ( $user->whitelabel_products as $wl_product){
foreach ($wl_product->whitelabel_images as $wl_image) {
$wl_image->update([
'attributes' => isset($data['image_wl_attributes'][$wl_image->id]) ? $data['image_wl_attributes'][$wl_image->id] : NULL,
]);
}
}
}
\Session()->flash('alert-save', true);
}
UserHistory::create(['user_id' => $user->id, 'action'=>'released_incomplete', 'status'=>0]);
\Session()->flash('alert-success', "E-Mail an Vertriebspartner gesendet.");
}
return redirect(route('admin_lead_edit', [$user->id]));
return redirect(route('admin_lead_edit', [$user->id])."?show=".$show);
}
public function remove($action, $user_id, $id, $mid=null){
$show = Request::get('show');
$user = User::findOrFail($user_id);
//send new verfified mail to user
public function newMailVerified($id){
$user = User::findOrFail($id);
$confirmation_code = UserService::createConfirmationCode();
$user->confirmation_code = $confirmation_code;
$user->confirmation_code_to = date('Y-m-d H:i:s', strtotime('+1 week'));
$user->confirmation_code_remider = 0;
$user->save();
try {
Mail::to($user->email)->send(new MailVerifyAccount($confirmation_code, $user));
if($action === 'remove_whitelabel_label'){
$model = $user->whitelabel_products()->where('id', $id)->first();
return \App\Services\ProductImage::imageDelete('user_wl_image', $model, $mid);
}
catch(\Exception $e){
SysLog::action('new_mail_verified', 'admin_lead', 5)
->setUserId($user->id)
->setModel($user->id, User::class)
->setMessage('Error send new_mail_verified E-Mail: '.$e->getMessage())
->save();
}
UserHistory::create(['user_id' => $user->id, 'action'=>'new_mail_verified', 'status'=>0]);
\Session()->flash('alert-success', "E-Mail erneut gesendet");
return redirect(route('admin_lead_edit', [$user->id]));
if($action === 'remove_whitelabel_product'){
$model = $user->whitelabel_products()->where('id', $id)->first();
//remove images
foreach ($model->whitelabel_images as $image){
\App\Services\ProductImage::imageDelete('user_wl_image', $model, $image->id);
}
$model->delete();
\Session()->flash('alert-success', "White Label Produkt entfernt");
return redirect(route('admin_lead_edit', [$user->id])."?show=$show");
}
}
public function deleteFile($user_id, $file_id, $relation){
public function download(){
if($relation === 'upload'){
$user = User::findOrFail($user_id);
$file = $user->files()->findOrFail($file_id);
//remove file
\Storage::disk('user')->delete($file->dir.$file->filename);
$file->delete();
\Session()->flash('alert-success', "Datei gelöscht");
if(Request::get('action') === "export"){
$query = $this->initSearch();
$columns = [];
$filename = "GS-VP-export-".date("d-m-Y");
$headers = array(
'ID',
'Email',
'Firma',
'Anrede',
'Vorname',
'Nachname',
'Mitglied',
'Bis',
'Art',
);
$objects = $query->get();
if($objects){
foreach ($objects as $obj){
$columns[] = array(
'ID' => $obj->id,
'Email' => $obj->email,
'Firma' => $obj->account ? $obj->account->company : '',
'Anrede' => $obj->account ? ($obj->account->salutation == 'mr' ? 'Herr' : 'Frau') : '-',
'Vorname' => $obj->account ? $obj->account->first_name : '',
'Nachname' => $obj->account ? $obj->account->last_name : '',
'Mitglied' => $obj->payment_account ? ($obj->isActiveAccount() ? 'JA' : 'Abgelaufen') : "Nein",
'Bis' => $obj->payment_account ? $obj->getPaymentAccountDateFormat(false) : '-',
'Art' => $obj->lead_type ? $obj->lead_type->name : '-',
);
}
}
return Excel::download(new ExcelExport($columns, $headers), $filename.'.xls');
}
return back();
}
private function setFilterVars(){
if(!session('filter_lead_type_id')){
session(['filter_lead_type_id' => 'all']);
}
if(Request::get('filter_lead_type_id')){
session(['filter_lead_type_id' => Request::get('filter_lead_type_id')]);
}
}
private function initSearch(){
$this->setFilterVars();
$query = User::with('account')->select('users.*')->where('users.deleted_at', '=', null)->where('users.admin', "<", 4);
if(session('filter_lead_type_id') && session('filter_lead_type_id') !== null && session('filter_lead_type_id') !== "all"){
$query->where('lead_type_id', session('filter_lead_type_id'));
}
return $query;
}
public function getLeads()
{
$query = User::with('account')->select('users.*')->where('users.deleted_at', '=', null)->where('users.admin', "<", 4);
$query = $this->initSearch();
return \DataTables::eloquent($query)
->addColumn('first_name', function (User $user) {
@ -370,6 +381,9 @@ class LeadController extends Controller
->addColumn('user_level', function (User $user) {
return $user->user_level ? $user->user_level->name : '';
})
->addColumn('lead_type', function (User $user) {
return $user->lead_type ? $user->lead_type->name : '';
})
->addColumn('id', function (User $user) {
return '<a href="' . route('admin_lead_edit', [$user->id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="far fa-edit"></span></a>';
})
@ -404,10 +418,217 @@ class LeadController extends Controller
->orderColumn('id', 'id $1')
->orderColumn('confirmed', 'confirmed $1')
->orderColumn('active', 'active $1')
->orderColumn('lead_type', 'lead_type_id $1')
->orderColumn('agreement', 'agreement $1')
->orderColumn('payment_account', 'payment_account $1')
//->orderColumn('payment_shop', 'payment_shop $1')
->rawColumns(['id', 'confirmed', 'active', 'agreement', 'payment_account'])
->make(true);
}
private function activeAccountPayment($user){
if($user->user_level){
if($user->user_level->payment_year){
//if true = payments
$user->wizard = 20;
$user->active = 1;
$user->active_date = now();
$user->confirmation_code = null;
$user->confirmation_code_to = null;
$user->confirmation_code_remider = 0;
$user->save();
}else{
//if false = no payments for 1 year
$user->wizard = 100;
$user->payment_account = \Carbon::now()->modify('1 year');
$user->active = 1;
$user->active_date = now();
$user->confirmation_code = null;
$user->confirmation_code_to = null;
$user->confirmation_code_remider = 0;
$user->save();
}
}
}
//user released when register is complete
public function released($action, $id){
$user = User::findOrFail($id);
if($action === 'completed'){
$validator = Validator::make(Request::all(), []);
/*if(!$user->m_sponsor){
$validator->errors()->add('m_sponsor', __('Vertriebspartner hat keinen Sponsor.'));
}*/
if(!$user->account->m_first_name){
$validator->errors()->add('m_first_name', __('Vertriebspartner hat keinen Vornamen.'));
}
if(!$user->account->m_last_name){
$validator->errors()->add('m_last_name', __('Vertriebspartner hat keinen Nachnamen.'));
}
if(!$user->m_level){
$validator->errors()->add('m_level', __('Vertriebspartner hat keine Rolle'));
}
if ($validator->errors()->count()) {
return back()->withErrors($validator)->withRequest(Request::all());
}
if(!$user->account->m_account){
$user->account->m_account = UserAccount::withTrashed()->max('m_account') +1;
$user->account->save();
}
//create PDF
$pdf = new ContractPDFRepository($user);
$pdf->_set('disk', 'user');
$pdf->_set('dir', '/'.$user->id.'/documents/');
$pdf->_set('user_id', $user->id);
$pdf->_set('identifier', 'contract');
$pdf->createContractPDF();
//set wizard to payments / activate
$this->activeAccountPayment($user);
//mail with code to user?
try {
Mail::to($user->email)->bcc(config('app.info_mail'))->send(new MailAccountActive($user));
}
catch(\Exception $e){
SysLog::action('released', 'admin_lead', 5)
->setUserId($user->id)
->setModel($user->id, User::class)
->setMessage('Error send released E-Mail: '.$e->getMessage())
->save();
}
UserHistory::create(['user_id' => $user->id, 'action'=>'released_completed', 'status'=>0]);
\Session()->flash('alert-success', "Vertriebspartner freigeschaltet!");
}
if($action === 'incomplete'){
//reset release
$confirmation_code = UserService::createConfirmationCode();
$user->confirmation_code = $confirmation_code;
$user->confirmation_code_to = date('Y-m-d H:i:s', strtotime('+1 week'));
$user->confirmation_code_remider = 0;
$user->wizard = 1;
$user->release_account = null;
$user->save();
$input = Request::all();
$data = [
'subject' => $input['account_incomplete_subject'],
'message' => $input['account_incomplete_message'],
'confirmation_code' => $confirmation_code,
];
try {
Mail::to($user->email)->bcc(config('app.info_mail'))->send(new MailCustomMessage($user, $data, \Auth::user(), true));
}
catch(\Exception $e){
SysLog::action('released_incomplete', 'admin_lead', 5)
->setUserId($user->id)
->setModel($user->id, User::class)
->setMessage('Error send released_incomplete E-Mail: '.$e->getMessage())
->save();
}
UserHistory::create(['user_id' => $user->id, 'action'=>'released_incomplete', 'status'=>0]);
\Session()->flash('alert-success', "E-Mail an Vertriebspartner gesendet.");
}
if($action === 'reset_switch'){
$user->wizard = 3;
$user->save();
UserHistory::create(['user_id' => $user->id, 'action'=>'reset_switch', 'status'=>0]);
\Session()->flash('alert-success', "Vertriebspartner zurückgesetzt!");
}
if($action === 'unlock'){
$validator = Validator::make(Request::all(), []);
/*if(!$user->m_sponsor){
$validator->errors()->add('m_sponsor', __('Vertriebspartner hat keinen Sponsor.'));
}*/
if(!$user->account->m_first_name){
$validator->errors()->add('m_first_name', __('Vertriebspartner hat keinen Vornamen.'));
}
if(!$user->account->m_last_name){
$validator->errors()->add('m_last_name', __('Vertriebspartner hat keinen Nachnamen.'));
}
if(!$user->m_level){
$validator->errors()->add('m_level', __('Vertriebspartner hat keine Rolle'));
}
if ($validator->errors()->count()) {
return back()->withErrors($validator)->withRequest(Request::all());
}
if(!$user->account->m_account){
$user->account->m_account = UserAccount::withTrashed()->max('m_account') +1;
$user->account->save();
}
//set wizard to payments / activate
$this->activeAccountPayment($user);
//mail with code to user?
try {
Mail::to($user->email)->bcc(config('app.info_mail'))->send(new MailAccountActive($user));
}
catch(\Exception $e){
SysLog::action('unlock', 'admin_lead', 5)
->setUserId($user->id)
->setModel($user->id, User::class)
->setMessage('Error send released E-Mail: '.$e->getMessage())
->save();
}
UserHistory::create(['user_id' => $user->id, 'action'=>'unlock_completed', 'status'=>0]);
\Session()->flash('alert-success', "Vertriebspartner erneut freigeschaltet!");
}
return redirect(route('admin_lead_edit', [$user->id]));
}
//send new verfified mail to user
/* public function newMailVerified($id){
User Register sind in der DB UserRegister, erst bei bestätigung wird es in die User DB übertragen
$user = User::findOrFail($id);
$confirmation_code = UserService::createConfirmationCode();
$user->confirmation_code = $confirmation_code;
$user->confirmation_code_to = date('Y-m-d H:i:s', strtotime('+1 week'));
$user->confirmation_code_remider = 0;
$user->save();
try {
Mail::to($user->email)->bcc(config('app.info_mail'))->send(new MailVerifyAccount($confirmation_code, $user));
}
catch(\Exception $e){
SysLog::action('new_mail_verified', 'admin_lead', 5)
->setUserId($user->id)
->setModel($user->id, User::class)
->setMessage('Error send new_mail_verified E-Mail: '.$e->getMessage())
->save();
}
UserHistory::create(['user_id' => $user->id, 'action'=>'new_mail_verified', 'status'=>0]);
\Session()->flash('alert-success', "E-Mail erneut gesendet");
return redirect(route('admin_lead_edit', [$user->id]));
}*/
public function deleteFile($user_id, $file_id, $relation){
if($relation === 'upload'){
$user = User::findOrFail($user_id);
$file = $user->files()->findOrFail($file_id);
//remove file
\Storage::disk('user')->delete($file->dir.$file->filename);
$file->delete();
\Session()->flash('alert-success', "Datei gelöscht");
}
return back();
}
}

View file

@ -0,0 +1,47 @@
<?php
namespace App\Http\Controllers;
use App\Models\LeadType;
use Request;
class LeadTypeController extends Controller
{
public function __construct()
{
$this->middleware('admin');
}
public function index()
{
$data = [
'values' => LeadType::all(),
];
return view('admin.lead.types', $data);
}
public function store()
{
$data = Request::all();
if($data['id'] === "new"){
$model = LeadType::create([
'name' => $data['name'],
'active' => isset($data['active']) ? true : false,
]);
}else{
$model = LeadType::find($data['id']);
$model->name = $data['name'];
$model->active = isset($data['active']) ? true : false;
$model->save();
}
\Session()->flash('alert-save', '1');
return redirect(route('admin_lead_types'));
}
}

View file

@ -51,7 +51,7 @@ class MembershipController extends Controller
'userHistoryPaymentOrder' => $userHistoryPaymentOrder,
'userHistoryUpgradeOrder' => $userHistoryUpgradeOrder,
'userHistoryDeleteMembership' => $userHistoryDeleteMembership,
'user_levels' => UserLevel::where('active', true)->get(),
'user_levels' => UserLevel::where('active', true)->orderBy('pos')->get(),
];
return view('user.membership.index', $data);
@ -99,6 +99,17 @@ class MembershipController extends Controller
$image = $product->images->first()->slug;
}
$qty = Request::get('qty') ? Request::get('qty') : 1;
/* //need setGlobalTaxRate
$cartItem = Yard::instance('shopping')->add($product->id, $product->getLang('name'), $qty, $product->getPriceWith(\App\Services\UserService::getTaxFree(), false, \App\Services\UserService::$user_country), false, false, ['image' => $image, 'slug' => $product->slug, 'weight' => $product->weight, 'points' => $product->points, 'no_commission' => $product->no_commission]);
if(\App\Services\UserService::getTaxFree()){
Yard::setTax($cartItem->rowId, 0);
}else{
Yard::setTax($cartItem->rowId, $product->getTaxWith(\App\Services\UserService::$user_country));
}
*/
//Keine steuer
Yard::instance('shopping')->add($product->id, $product->getLang('name'), $qty, $product->price, $product->tax, ['image' => $image, 'slug' => $product->slug, 'weight' => $product->weight]);
Yard::instance('shopping')->setGlobalTaxRate(0);
/*
@ -161,6 +172,8 @@ class MembershipController extends Controller
if($action === "change_level"){
if(Request::get('switchers-package-level')){
$user = User::find(Auth::user()->id);
//hier wird die nächste Mitgliedschaftsstufe gesetzt
//wird im Cronjob UserCheckPaymentsAccounts.php verwendet und gesetzt
$user->next_m_level = Request::get('switchers-package-level');
$user->save();
UserHistory::create(['user_id' => $user->id, 'action'=>$action, 'status'=>10, 'referenz'=>Request::get('switchers-package-level')]);

View file

@ -27,7 +27,7 @@ class ModalController extends Controller
if(Request::ajax()){
if($data['action'] === 'shopping-order-change-member'){
$value = ShoppingOrder::find($data['id']);
$route = route('admin_sales_customers_detail', [$value->id]);
$route = route('admin_sales_detail', [$value->id]);
$ret = view("admin.modal.member", compact('value', 'data', 'route'))->render();
}
if($data['action'] === 'shopping-user-change-member'){

View file

@ -59,6 +59,8 @@ class PayController extends Controller
private $reference;
private $payment_method;
public function __construct() {
}
@ -77,6 +79,7 @@ class PayController extends Controller
public function setPrePayment($payment_method, $amount, $currency, $ret = []){
$this->reference = $this->shopping_order->created_at->format('Ym').$this->shopping_order->id;//substr(uniqid('m', false), 0, 16);
$this->payment_method = $payment_method;
$this->setMethod($payment_method, $ret);
$this->prepayment = [
@ -86,7 +89,6 @@ class PayController extends Controller
"param" => $this->shopping_order->id,
];
$this->shopping_payment = ShoppingPayment::create([
'shopping_order_id' => $this->shopping_order->id,
'clearingtype' => $this->method["clearingtype"],
@ -119,6 +121,15 @@ class PayController extends Controller
private function setMethod($payment_method, $ret = []){
//vorkasse
if($payment_method === 'non'){
$this->method = [
"clearingtype" => "non",
"wallettype" => "",
'onlinebanktransfertype' => "",
"request" => "authorization",
];
}
if($payment_method === 'vor'){
$this->method = [
"clearingtype" => "vor",
@ -138,12 +149,21 @@ class PayController extends Controller
];
}
//Rechnungskauf
if($payment_method === 'pp'){
$this->method = [
"clearingtype" => "pp",
"wallettype" => "",
'onlinebanktransfertype' => "",
"request" => "CAPTURE",
];
}
}
public function ResponseData($identifier){
public function ResponseData($identifier, $payment_for = false){
$request = array_merge($this->default, $this->personalData, $this->deliveryData, $this->method, $this->prepayment, $this->urls);
//RECHNUNG MIV
$payt = PaymentTransaction::create([
'shopping_payment_id' => $this->shopping_payment->id,
@ -155,10 +175,36 @@ class PayController extends Controller
'txaction' => 'prev',
'mode' => $this->shopping_payment->mode,
]);
//paypal
if($this->payment_method === 'pp'){
switch ($payment_for) {
case 7: //promotion
$paypal = new PayPalController;
$redirect = $paypal->payment($this->shopping_payment, $payt, $identifier, $payment_for, $this->shopping_order->promotion_user_id);
Util::setUserHistoryValue(['status'=>4], $identifier);
return $redirect;
case 8: //shop
$paypal = new PayPalController;
$redirect = $paypal->payment($this->shopping_payment, $payt, $identifier, $payment_for, $this->shopping_order->user_shop_id);
Util::setUserHistoryValue(['status'=>4], $identifier);
return $redirect;
}
}
Util::setUserHistoryValue(['status'=>5], $identifier);
return redirect(route('user_checkout_final', [$payt->id, $this->reference, $identifier]));
switch ($payment_for) {
case 7: //promotion
return redirect(route('web_promotion_goto', ['thanksorder', $this->shopping_order->promotion_user_id, $payt->id, $this->reference, $identifier]));
break;
case 8: //shop
return redirect(route('web_shop_goto', ['thanksorder', $this->shopping_order->user_shop_id, $payt->id, $this->reference, $identifier]));
break;
default:
return redirect(route('user_checkout_final', [$payt->id, $this->reference, $identifier]));
break;
}
}
}

View file

@ -0,0 +1,113 @@
<?php
namespace App\Http\Controllers\Pay;
use Request;
use App\Models\UserShop;
use App\Models\PromotionUser;
use App\Models\PaymentTransaction;
use App\Http\Controllers\Controller;
use Srmklive\PayPal\Services\PayPal as PayPalClient;
class PayPalController extends Controller
{
public function payment($shopping_payment, $payt, $identifier, $payment_for, $payment_for_user_id)
{
$provider = new PayPalClient;
// Through facade. No need to import namespaces
$provider = \PayPal::setProvider();
$provider->setApiCredentials(config('paypal'));
$provider->setAccessToken($provider->getAccessToken());
$provider->setCurrency('EUR');
$order = $provider->createOrder([
"intent"=> "CAPTURE",
"purchase_units"=> [
[
"reference_id" => $shopping_payment->reference,
"shopping_order_id" => $shopping_payment->shopping_order_id,
"amount"=> [
"currency_code"=> "EUR",
"value"=> ($shopping_payment->amount / 100)
],
'description' => 'test'
]
],
'application_context' => [
'cancel_url' => route('cancel.paypal_payment', [$payment_for, $payment_for_user_id, $payt->id, $shopping_payment->reference, $identifier]),
'return_url' => route('success.paypal_payment', [$payment_for, $payment_for_user_id, $payt->id, $shopping_payment->reference, $identifier])
]
]);
$payt->key = $order['id'];
$payt->save();
return redirect($order['links'][1]['href'])->send();
}
public function paymentSuccess($payment_for, $id, $transactionId=false, $reference=false, $identifier=false)
{
$payt = PaymentTransaction::findOrFail($transactionId);
if($payt->shopping_payment->reference != $reference){
abort(404);
}
// Init PayPal
$provider = \PayPal::setProvider();
$provider->setApiCredentials(config('paypal'));
$provider->setAccessToken($provider->getAccessToken());
// Get PaymentOrder using our transaction ID
$order = $provider->capturePaymentOrder($payt->key);
if(isset($order['type'])){
abort(403, 'PayPal Type: '.$order['type']);
}
if(!isset($order['status']) || $order['status'] !== "COMPLETED"){
abort(403, 'Error: Order Status ');
}
if(Request::get('token') !== $payt->key){
abort(403, 'Error: PayPal token');
}
$payt->request = $order['status'];
$payt->save();
switch ($payment_for) {
case 7: //promotion
$PromotionUser = PromotionUser::findOrFail($id);
return redirect(route('web_promotion_goto', ['thanksorder', $id, $payt->id, $reference, $identifier]));
case 8: //shop
$userShop = UserShop::findOrFail($id);
return redirect(route('web_shop_goto', ['thanksorder', $id, $payt->id, $reference, $identifier]));
dd('Your payment has been declend. The payment cancelation page goes here!');
}
}
public function paymentCancel($payment_for, $id, $transactionId=false, $reference=false, $identifier=false)
{
switch ($payment_for) {
case 7: //promotion
$PromotionUser = PromotionUser::findOrFail($id);
return redirect(url($PromotionUser->url));
dd('Your payment has been declend. The payment cancelation page goes here!');
case 8: //shop
$userShop = UserShop::findOrFail($id);
return redirect(url($userShop->url));
dd('Your payment has been declend. The payment cancelation page goes here!');
}
}
}

View file

@ -4,17 +4,18 @@
namespace App\Http\Controllers;
use App\Models\Models\UserCreditMargin as ModelsUserCreditMargin;
use Carbon;
use Request;
use App\User;
use App\Services\Util;
use App\Services\Credit;
use App\Services\Payment;
use App\Models\UserCredit;
use App\Models\ShoppingOrderMargin;
use App\Models\UserCredit;
use App\Models\UserCreditMargin;
use App\Repositories\CreditRepository;
use App\Services\Credit;
use App\Services\Payment;
use App\Services\Payment\UserBot;
use App\Services\Util;
use App\User;
use Carbon;
use Illuminate\Support\Collection;
use Request;
class PaymentCreditController extends Controller
{
@ -23,10 +24,12 @@ class PaymentCreditController extends Controller
private $endYear;
private $rangeYears;
private $activeYear;
private $userBot;
public function __construct()
public function __construct(UserBot $userBot)
{
$this->middleware('auth');
$this->userBot = $userBot;
$this->startYear = 2021;
$this->endYear = date('Y');
$this->rangeYears = range($this->startYear, $this->endYear);
@ -41,7 +44,11 @@ class PaymentCreditController extends Controller
}
/**
* fügt eine neue Manuelle Gutschrift hinzu
*
* @return \Illuminate\Http\RedirectResponse
*/
public function store(){
$data = Request::all();
@ -64,7 +71,6 @@ class PaymentCreditController extends Controller
$credit = Util::reFormatNumber($data['credit']);
$credit = number_format($credit, 2, '.', '');
Payment::addUserCreditMargin($user, $credit, 3, $data['message']);
\Session()->flash('alert-success', "Guthaben hinzugefügt");
}
@ -72,6 +78,11 @@ class PaymentCreditController extends Controller
return redirect(route('admin_payments_credit'));
}
/**
* Erstellt eine neue komplette Gutschrift für einen Benutzer
*
* @return \Illuminate\Http\RedirectResponse
*/
public function create(){
$data = Request::all();
if(isset($data['action'])){
@ -95,65 +106,18 @@ class PaymentCreditController extends Controller
}
}
private function makeData(){
private function makeData(): array
{
$this->setActiveYears();
//$date1 = Carbon::parse('01.01.'.$this->activeYear." 00:00:00")->format('Y-m-d H:i:s');
//$date2 = Carbon::parse('31.12.'.$this->activeYear." 23:59:59")->toDateString();
$this->userBot->readUserHasCredits();
$this->userBot->readUserHasPendingCredit();
$ShoppingOrderMargins = ShoppingOrderMargin::join('users', 'm_sponsor_id', '=', 'users.id')
->groupBy('m_sponsor_id')
->join('user_accounts', 'account_id', '=', 'user_accounts.id')
->select('users.id as user_id', 'users.email', 'user_accounts.first_name', 'user_accounts.last_name')
->wherePaid(true)
->whereCancellation(false)
->wherePartnerCommissionPaid(false)
->where('partner_commission_pending_to', '<', Carbon::now())
->get();
$ShoppingOrderMarginPendings = ShoppingOrderMargin::join('users', 'm_sponsor_id', '=', 'users.id')
->groupBy('m_sponsor_id')
->join('user_accounts', 'account_id', '=', 'user_accounts.id')
->select('users.id as user_id', 'users.email', 'user_accounts.first_name', 'user_accounts.last_name')
->wherePaid(true)
->whereCancellation(false)
->wherePartnerCommissionPaid(false)
->where('partner_commission_pending_to', '>=', Carbon::now())
->get();
$UserCreditMargins = UserCreditMargin::wherePaid(false)->get();
$ShoppingOrderMarginUserIds = ShoppingOrderMargin::select('m_sponsor_id')->groupBy('m_sponsor_id')
->wherePaid(true)
->whereCancellation(false)
->wherePartnerCommissionPaid(false)
->where('partner_commission_pending_to', '<', Carbon::now())
->get()->pluck('m_sponsor_id')->toArray();
$onlyUserCreditMargins = [];
foreach($UserCreditMargins as $key => $UserCreditMargin){
if(!in_array($UserCreditMargin->user_id, $ShoppingOrderMarginUserIds)){
if(isset($onlyUserCreditMargins[$UserCreditMargin->user_id])){
$onlyUserCreditMargins[$UserCreditMargin->user_id]['sum'] += $UserCreditMargin->credit;
$onlyUserCreditMargins[$UserCreditMargin->user_id]['entries'][$UserCreditMargin->id] = $UserCreditMargin;
}else{
$onlyUserCreditMargins[$UserCreditMargin->user_id] = [
'user_id' => $UserCreditMargin->user->id,
'first_name' => $UserCreditMargin->user->account->first_name,
'last_name' => $UserCreditMargin->user->account->last_name,
'email' => $UserCreditMargin->user->email,
'sum' => $UserCreditMargin->credit,
'entries' => [$UserCreditMargin->id => $UserCreditMargin],
];
}
}
}
$data = [
return [
'years' => $this->rangeYears,
'active_year' => $this->activeYear,
'ShoppingOrderMargins' => $ShoppingOrderMargins,
'ShoppingOrderMarginPendings' => $ShoppingOrderMarginPendings,
'onlyUserCreditMargins' => $onlyUserCreditMargins,
'users_credits' => $this->userBot->getUsers(),
'users_credits_pending' => $this->userBot->getUsersPending(),
];
return $data;
}
private function setActiveYears(){
@ -173,19 +137,25 @@ class PaymentCreditController extends Controller
\Session()->flash('alert-error', "Guthaben kann nicht gelöscht werden");
}
}
if($del === 'shopping_order_margin'){
$ShoppingOrderMargin = ShoppingOrderMargin::findOrFail($id);
$ShoppingOrderMargin->out_paid = true;
$ShoppingOrderMargin->save();
\Session()->flash('alert-success', "Gutschrift ist gelöscht");
}
return redirect(route('admin_payments_credit'));
}
public function datatable(){
$this->setActiveYears();
$date1 = Carbon::parse('01.01.'.$this->activeYear)->format('Y-m-d');
$date2 = Carbon::parse('31.12.'.$this->activeYear)->format('Y-m-d');
$startDate = Carbon::parse("01.01.{$this->activeYear}")->format('Y-m-d');
$endDate = Carbon::parse("31.12.{$this->activeYear}")->format('Y-m-d');
$query = UserCredit::with('user', 'user.account')->select('user_credits.*')
//::with('shopping_user', )->select('shopping_orders.*')
//->where('paid', '=', 1)
->whereBetween('date', [$date1, $date2]);
->whereBetween('date', [$startDate, $endDate]);
//->orderBy('created_at', 'DESC');
return \DataTables::eloquent($query)

View file

@ -62,7 +62,7 @@ class PaymentInvoiceController extends Controller
return \DataTables::eloquent($query)
->addColumn('id', function (ShoppingOrder $ShoppingOrder) {
return '<a href="' . route('admin_sales_customers_detail', [$ShoppingOrder->id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
return '<a href="' . route('admin_sales_detail', [$ShoppingOrder->id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
})
->addColumn('total_shipping', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->getFormattedTotalShipping()."";
@ -80,6 +80,9 @@ class PaymentInvoiceController extends Controller
->addColumn('txaction', function (ShoppingOrder $ShoppingOrder) {
return Payment::getShoppingOrderBadge($ShoppingOrder);
})
->addColumn('payment_for', function (ShoppingOrder $ShoppingOrder) {
return Payment::getPaymentForTypeBadge($ShoppingOrder);
})
->addColumn('invoice', function (ShoppingOrder $ShoppingOrder) {
$ret = "";
if(Invoice::isInvoice($ShoppingOrder)){
@ -95,8 +98,9 @@ class PaymentInvoiceController extends Controller
->orderColumn('invoice_number', 'invoice_number $1')
->orderColumn('txaction', 'txaction $1')
->orderColumn('shipped', 'shipped $1')
->orderColumn('payment_for', 'payment_for $1')
->orderColumn('total_shipping', 'total_shipping $1')
->rawColumns(['id', 'shipping_order', 'txaction', 'invoice'])
->rawColumns(['id', 'shipping_order', 'txaction', 'payment_for', 'invoice'])
->make(true);
}
}

View file

@ -4,7 +4,6 @@ namespace App\Http\Controllers;
use App\Models\PaymentMethod;
use App\Models\UserLevel;
use Request;

View file

@ -0,0 +1,147 @@
<?php
namespace App\Http\Controllers;
use Carbon;
use Request;
use App\Models\PaymentReminder;
use App\Models\ShoppingPayment;
use App\Services\PaymentReminderService;
class PaymentReminderController extends Controller
{
private $filter_user_status;
private $paymentReminderService;
public function __construct(PaymentReminderService $paymentReminderService)
{
$this->middleware('auth');
$this->paymentReminderService = $paymentReminderService;
}
public function index()
{
// Hole die detaillierten Daten für die Tabellen-Ansicht
$detailedData = $this->paymentReminderService->getDetailedPaymentsData();
// $summaryData = $this->paymentReminderService->getAllOpenPayments();
// Statistiken für die Übersicht
$totalPayments = collect($detailedData)->count();
$totalAmount = collect($detailedData)->sum('amount')/100;
$clearingTypes = collect($detailedData)->groupBy('clearingtype')->map->count();
$data = [
'reminders' => PaymentReminder::all(),
'detailedData' => $detailedData,
//'summaryData' => $summaryData,
'totalPayments' => $totalPayments,
'totalAmount' => $totalAmount,
'clearingTypes' => $clearingTypes,
];
return view('admin.payment.reminder.index', $data);
}
public function create()
{
$reminder = new PaymentReminder();
$reminder->active = true;
$data = [
'reminder' => $reminder,
];
return view('admin.payment.reminder.edit', $data);
}
public function edit($id)
{
$data = [
'reminder' => PaymentReminder::find($id),
];
return view('admin.payment.reminder.edit', $data);
}
public function store()
{
$data = Request::all();
$data['active'] = isset($data['active']) ? true : false;
$data['action'] = isset($data['action']) ? $data['action'] : NULL;
if ($data['id'] === 'new') {
PaymentReminder::create($data);
} else {
$reminder = PaymentReminder::find($data['id']);
$reminder->update($data);
}
return redirect()->route('admin_payments_reminder')->with('success', 'Erinnerung gespeichert');
}
public function action($action, $id)
{
$payment = ShoppingPayment::find($id);
if($action == 'send_reminder'){
$bool = $this->paymentReminderService->sendReminder($payment);
if($bool){
\Session()->flash('alert-success', "Zahlungserinnerung gesendet");
}else{
\Session()->flash('alert-error', "Keine Zahlungserinnerung gesendet");
}
}
if($action == 'no_payment'){
$this->paymentReminderService->setNoNPayment($payment);
\Session()->flash('alert-success', "Zahlung als nicht bezahlt markiert");
}
return redirect()->route('admin_payments_reminder');
}
public function delete($id)
{
$reminder = PaymentReminder::find($id);
$reminder->delete();
return redirect()->route('admin_payments_reminder');
}
public function logs()
{
// Hole die Log-Statistiken für verschiedene Zeiträume
$stats7Days = $this->paymentReminderService->getLogStatistics(7);
$stats30Days = $this->paymentReminderService->getLogStatistics(30);
$stats90Days = $this->paymentReminderService->getLogStatistics(90);
// Hole die neuesten Logs
$recentLogs = $this->paymentReminderService->getPaymentReminderLogs(50);
// Filter-Parameter
$orderId = Request::get('order_id');
$action = Request::get('action');
$startDate = Request::get('start_date');
$endDate = Request::get('end_date');
// Gefilterte Logs
$filteredLogs = null;
if ($orderId || $action || $startDate || $endDate) {
if ($startDate && $endDate) {
$filteredLogs = $this->paymentReminderService->getLogsForDateRange($startDate, $endDate);
} elseif ($orderId) {
$filteredLogs = $this->paymentReminderService->getLogsForPayment($orderId);
} elseif ($action) {
$filteredLogs = $this->paymentReminderService->getPaymentReminderLogs(100, null, $action);
}
}
$data = [
'stats7Days' => $stats7Days,
'stats30Days' => $stats30Days,
'stats90Days' => $stats90Days,
'recentLogs' => $recentLogs,
'filteredLogs' => $filteredLogs,
'orderId' => $orderId,
'action' => $action,
'startDate' => $startDate,
'endDate' => $endDate,
];
return view('admin.payment.reminder.logs', $data);
}
}

View file

@ -3,6 +3,8 @@
namespace App\Http\Controllers;
use App\Models\Country;
use App\Models\Ingredient;
use App\Models\PackagingItem;
use App\Models\Product;
use App\Models\ProductImage;
use App\Models\ProductIngredient;
@ -10,49 +12,52 @@ use App\Repositories\ProductRepository;
use Request;
use Validator;
class ProductController extends Controller
{
protected $productRepo;
public function __construct(ProductRepository $productRepo)
{
$this->middleware('admin');
$this->middleware('copyreader');
$this->productRepo = $productRepo;
}
public function index()
{
if(Request::get('show_active_products')){
if (Request::get('show_active_products')) {
set_user_attr('show_active_products', Request::get('show_active_products'));
}
if(get_user_attr('show_active_products') === "true"){
if (get_user_attr('show_active_products') === 'true') {
$values = Product::where('active', true)->orderBy('pos', 'DESC')->orderBy('id', 'DESC')->get();
}else{
} else {
$values = Product::orderBy('pos', 'DESC')->orderBy('id', 'DESC')->get();
}
$data = [
'values' => $values
'values' => $values,
];
return view('admin.product.index', $data);
}
public function edit($id)
{
if($id === "new"){
$model = new Product();
if ($id === 'new') {
$model = new Product;
$model->active = true;
}else{
} else {
$model = Product::findOrFail($id);
$model->load(['packagings.packagingMaterial']);
}
$country_for_prices = Country::where('own_eur', '=', true)->orWhere('currency', '=', true)->get();
$data = [
'product' => $model,
'country_for_prices' => $country_for_prices,
'ingredient_catalog' => Ingredient::query()->where('active', true)->with('materialQuality')->orderBy('name')->get(['id', 'name', 'inci', 'effect', 'default_factor', 'material_quality_id']),
'packaging_catalog' => PackagingItem::query()->where('active', true)->with('packagingMaterial')->orderBy('name')->get(),
];
return view('admin.product.edit', $data);
}
@ -61,34 +66,36 @@ class ProductController extends Controller
$data = Request::all();
$rules = array(
$rules = [
'name' => 'required',
);
];
/*if(isset($data['number']) && $data['number'] != ""){
$rules['number'] = 'int';
}*/
if(isset($data['wp_number'])){
if($data['id'] !== "new"){
if (isset($data['wp_number'])) {
if ($data['id'] !== 'new') {
$model = Product::findOrFail($data['id']);
$rules['wp_number'] = 'unique:products,wp_number,'.$model->id;
}else{
} else {
$rules['wp_number'] = 'unique:products,wp_number';
}
}
$validator = Validator::make(Request::all(), $rules);
if($data['id'] === "new"){
$model = new Product();
}else{
if ($data['id'] === 'new') {
$model = new Product;
} else {
$model = Product::findOrFail($data['id']);
$model->load(['packagings.packagingMaterial']);
}
$country_for_prices = Country::where('own_eur', '=', true)->orWhere('currency', '=', true)->get();
$data = [
'product' => $model,
'country_for_prices' => $country_for_prices,
'ingredient_catalog' => Ingredient::query()->where('active', true)->with('materialQuality')->orderBy('name')->get(['id', 'name', 'inci', 'effect', 'default_factor', 'material_quality_id']),
'packaging_catalog' => PackagingItem::query()->where('active', true)->with('packagingMaterial')->orderBy('name')->get(),
];
if ($validator->fails()) {
@ -98,119 +105,68 @@ class ProductController extends Controller
} else {
$product = $this->productRepo->update(Request::all());
\Session()->flash('alert-save', true);
return redirect(route('admin_product_edit', [$product->id]));
}
\Session()->flash('alert-save', '1');
return redirect(route('admin_product_show'));
}
public function copy($id){
public function copy($id)
{
$model = Product::findOrFail($id);
$product = $this->productRepo->copy($model);
\Session()->flash('alert-success', 'Eintrag kopiert');
return redirect(route('admin_product_show'));
}
public function delete($id, $do = 'product', $did = null){
if($do === 'product'){
public function delete($id, $do = 'product', $did = null)
{
if ($do === 'product') {
$model = Product::findOrFail($id);
$model->delete();
\Session()->flash('alert-success', 'Eintrag gelöscht');
return redirect(route('admin_product_show'));
}
if($do === 'ingredient'){
if ($do === 'ingredient') {
$model = Product::findOrFail($id);
$ProductIngredient = ProductIngredient::where('ingredient_id', $did)->where('product_id', $model->id)->first();
if($ProductIngredient){
$ProductIngredient->delete();
$productIngredient = ProductIngredient::where('ingredient_id', $did)->where('product_id', $model->id)->first();
if ($productIngredient) {
$productIngredient->delete();
\Session()->flash('alert-success', 'Eintrag gelöscht');
return redirect(route('admin_product_edit', [$model->id]));
}
return redirect(route('admin_product_edit', [$model->id]));
}
abort(404);
}
// Upload FILE -----------------------------------------------------------------------------------------------------------------------
public function imageUpload(){
public function imageUpload()
{
$product_id = Request::get('product_id');
$product = Product::findOrFail($product_id);
try {
$image = \App\Services\Slim::getImages('images')[0];
if ( isset($image['output']['data']) )
{
// Base64 of the image
$data = $image['output']['data'];
$file_ex = array( 'image/jpeg' => 'jpg', 'image/png' => 'png');
if (!isset($file_ex[$image['output']['type']])) {
\Session()->flash('alert-danger', 'File is not jpg or png!');
return redirect(route('admin_product_edit', [$product->id]));
}
$ext = $file_ex[$image['output']['type']];
// Original file name
$name = $image['output']['name'];
$name = \App\Services\Slim::sanitizeFileName($name);
$name = uniqid() . '_' . $name;
$data = \Storage::disk('public')->put(
'images/product/'.$product->id.'/'.$name,
$data
);
ProductImage::create([
'product_id' => $product->id,
'filename' => $name,
'original_name' => $image['output']['name'],
'ext' => $ext,
'mine' => $image['output']['type'],
'size' => $image['input']['size']
]);
\Session()->flash('alert-success', "Datei hochgeladen");
return redirect(route('admin_product_edit', [$product->id]));
}
\Session()->flash('alert-danger', "Datei leer");
return redirect(route('admin_product_edit', [$product->id]));
if (Request::has('product_id')) {
$product = Product::findOrFail(Request::get('product_id'));
return \App\Services\ProductImage::imageUpload('product', $product, Request::get('upload_type'));
}
catch (\Exception $e) {
\Session()->flash('alert-danger', "Fehler".$e);
return redirect(route('admin_product_edit', [$product->id]));
}
}
public function imageDelete($image_id, $product_id){
$product = Product::findOrFail($product_id);
$product_image = ProductImage::findOrFail($image_id);
if($product_image->product_id == $product->id){
$file = 'images/product/'.$product->id.'/'.$product_image->filename;
\Storage::disk('public')->delete($file);
$product_image->delete();
\Session()->flash('alert-success', "Datei gelöscht");
return redirect(route('admin_product_edit', [$product->id]));
}
\Session()->flash('alert-danger', "Datei nicht gefunden");
return redirect(route('admin_product_edit', [$product->id]));
}
public function imageAttribute($product_id, $attr, $val = false){
public function imageDelete($product_image_id, $product_id)
{
$product = Product::findOrFail($product_id);
if(is_numeric($val) && $val < 0){
return \App\Services\ProductImage::imageDelete('product', $product, $product_image_id);
}
public function imageAttribute($product_id, $attr, $val = false)
{
if (is_numeric($val) && $val < 0) {
$val = 0;
}
@ -219,9 +175,9 @@ class ProductController extends Controller
$product_image->{$attr} = $val;
$product_image->save();
\Session()->flash('alert-success', "Wert gespeichert");
\Session()->flash('alert-success', 'Wert gespeichert');
return redirect()->back();
}
}

View file

@ -2,26 +2,197 @@
namespace App\Http\Controllers;
use Request;
use App\Models\Setting;
use App\Models\UserShop;
use App\Services\Payment;
use App\Models\ShoppingUser;
use App\Models\ShoppingOrder;
use App\Models\UserPayCredit;
use App\Models\ShoppingPayment;
use App\Models\PaymentTransaction;
use App\Services\CustomerPriority;
use App\Models\ShoppingUser;
use App\Repositories\InvoiceRepository;
use App\Services\CustomerPriority;
use App\Services\Invoice;
use App\Services\Payment;
use App\Services\PaymentService;
use Request;
class SalesController extends Controller
{
public function __construct(){
public function __construct()
{
$this->middleware('admin');
}
public function users(){
public function index()
{
if (Request::get('reset') === 'filter') {
set_user_attr('filter_txaction', null);
set_user_attr('filter_member_id', null);
set_user_attr('filter_art', null);
set_user_attr('filter_shipped', null);
return redirect(route('admin_sales'));
}
// set Filter!
$filter_members = ShoppingOrder::join('users', 'member_id', '=', 'users.id')->groupBy('member_id')->join('user_accounts', 'account_id', '=', 'user_accounts.id')->select('users.id', 'users.email', 'user_accounts.first_name', 'user_accounts.last_name')->get();
$data = [
'filter_members' => $filter_members,
];
return view('admin.sales.index', $data);
}
public function detail($id)
{
$ShoppingOrder = ShoppingOrder::find($id);
if ($ShoppingOrder->shipped == 0) {
$ShoppingOrder->shipped = 1;
$ShoppingOrder->save();
}
$data = [
'shopping_order' => $ShoppingOrder,
'isAdmin' => true,
'isView' => $ShoppingOrder->auth_user_id ? 'sales_user' : 'sales_customer',
];
return view('admin.sales.detail', $data);
}
public function detailStore($id)
{
$data = Request::all();
$change_member_error = false;
if ($data['action'] === 'shopping-order-change-member') {
if (! isset($data['change_member_key']) || $data['change_member_key'] !== config('main.edit_data_pass')) {
$change_member_error = 'Das Passwort ist falsch.';
} else {
// change
$shopping_order = ShoppingOrder::findOrFail($data['id']);
CustomerPriority::newMemberForOrder($shopping_order, $data['change_member_id'], $data['customer_set_member_for']);
\Session()->flash('alert-save', true);
return redirect(route('admin_sales_detail', [$shopping_order->id]));
}
}
if ($data['action'] === 'shopping-user-is-like-member') {
if (! isset($data['change_member_key']) || $data['change_member_key'] !== config('main.edit_data_pass')) {
\Session()->flash('alert-error', 'Das Passwort ist falsch.');
return redirect($data['back']);
} else {
if (! isset($data['is_like_shopping_user_id'])) {
\Session()->flash('alert-error', 'Keine Änderung ausgewählt');
return redirect($data['back']);
}
$shopping_user = ShoppingUser::findOrFail($data['id']);
$set_like_shopping_user = ShoppingUser::findOrFail($data['is_like_shopping_user_id']);
$send_member_mail = isset($data['send_member_mail']) ? true : false;
$change_shopping_user = isset($data['change_shopping_user']) ? true : false;
// Mail send in setIsLike
CustomerPriority::setIsLike($shopping_user, $set_like_shopping_user, $send_member_mail, $change_shopping_user);
\Session()->flash('alert-save', true);
return redirect($data['back']);
}
}
$ShoppingOrder = ShoppingOrder::find($id);
$data = [
'change_member_error' => $change_member_error,
'shopping_order' => $ShoppingOrder,
'isAdmin' => true,
'isView' => $ShoppingOrder->auth_user_id ? 'sales_user' : 'sales_customer',
];
return view('admin.sales.detail', $data);
}
public function datatable()
{
$query = ShoppingOrder::with('shopping_user', 'shopping_payments')->select('shopping_orders.*');
set_user_attr('filter_txaction', Request::get('filter_txaction'));
if (Request::get('filter_txaction') != '') {
if (Request::get('filter_txaction') === 'NULL') {
$query->where('txaction', '=', null);
} else {
$query->where('txaction', '=', Request::get('filter_txaction'));
}
}
set_user_attr('filter_member_id', Request::get('filter_member_id'));
if (Request::get('filter_member_id') != '') {
$query->where('member_id', '=', Request::get('filter_member_id'));
}
set_user_attr('filter_art', Request::get('filter_art'));
if (Request::get('filter_art') != '') {
if (Request::get('filter_art') === 'user_order') {
$query->where('shopping_orders.auth_user_id', '!=', null)->where('payment_for', '!=', 6);
} elseif (Request::get('filter_art') === 'customer_order') {
$query->where('shopping_orders.auth_user_id', null);
} elseif (Request::get('filter_art') === 'user_for_customer') {
$query->where('shopping_user_id', '!=', null)->where('payment_for', '=', 6);
}
// $query->where('payment_for', '=', Request::get('filter_art'));
}
set_user_attr('filter_shipped', Request::get('filter_shipped'));
if (Request::get('filter_shipped') != '') {
$query->where('shipped', '=', Request::get('filter_shipped'));
}
return \DataTables::eloquent($query)
->addColumn('id', function (ShoppingOrder $ShoppingOrder) {
return '<a href="'.route('admin_sales_detail', [$ShoppingOrder->id]).'" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
})
->addColumn('created_at', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->created_at->format('d.m.Y');
})
->addColumn('txaction', function (ShoppingOrder $ShoppingOrder) {
return Payment::getShoppingOrderBadge($ShoppingOrder);
})
->addColumn('total_shipping', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->getFormattedTotalShipping().' €';
})
->addColumn('payment', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->getLastShoppingPayment('getPaymentType');
})
->addColumn('shipped', function (ShoppingOrder $ShoppingOrder) {
return '<span class="badge badge-pill badge-'.$ShoppingOrder->getShippedColor().'">'.$ShoppingOrder->getShippedType().'</span>';
})
->addColumn('payment_for', function (ShoppingOrder $ShoppingOrder) {
return Payment::getPaymentForTypeBadge($ShoppingOrder);
})
->addColumn('reference', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->getLastShoppingPayment('reference');
})
->addColumn('member_id', function (ShoppingOrder $ShoppingOrder) {
if ($ShoppingOrder->member_id) {
return $ShoppingOrder->member_id ? '<a href="'.route('admin_lead_edit', [$ShoppingOrder->member_id]).'">'.$ShoppingOrder->member->getFullName().'</a>' : '';
}
if ($ShoppingOrder->shopping_user && $ShoppingOrder->shopping_user->is_like) {
return '<button type="button" class="btn btn-xs btn-outline-info" data-toggle="modal" data-target="#modals-load-content"
data-id="'.$ShoppingOrder->shopping_user->id.'"
data-action="shopping-user-is-like-member"
data-back="'.route('admin_sales').'"
data-modal="modal-xl"
data-route="'.route('modal_load').'"><span class="fa fa-edit"></span> Vertriebspartner zuordnen</button>';
}
return '';
})
->orderColumn('id', 'id $1')
->orderColumn('txaction', 'txaction $1')
->orderColumn('payment_for', 'payment_for $1')
->orderColumn('member_id', 'member_id $1')
->orderColumn('shipped', 'shipped $1')
->orderColumn('total_shipping', 'total_shipping $1')
->rawColumns(['id', 'member_id', 'txaction', 'user_shop_id', 'payment_for', 'shipped'])
->make(true);
}
/*public function users(){
if(Request::get('reset') === 'filter'){
return redirect(route('admin_sales_users'));
@ -81,17 +252,8 @@ class SalesController extends Controller
->addColumn('shipped', function (ShoppingOrder $ShoppingOrder) {
return '<span class="badge badge-pill badge-'.$ShoppingOrder->getShippedColor().'">'.$ShoppingOrder->getShippedType().'</span>';
})
->addColumn('is_for', function (ShoppingOrder $ShoppingOrder) {
if($ShoppingOrder->shopping_user->is_for === 'me'){
return '<span class="badge badge-pill badge-secondary">Vertriebspartnerbestellung</span>';
}
if($ShoppingOrder->shopping_user->is_for === 'ot'){
return '<span class="badge badge-pill badge-info">Kundenbestellung</span>';
}
if($ShoppingOrder->shopping_user->is_for === 'hp'){
return '<span class="badge badge-pill badge-dark">Homepartybestellung</span>';
}
return '-';
->addColumn('payment_for', function (ShoppingOrder $ShoppingOrder) {
return Payment::getPaymentForTypeBadge($ShoppingOrder);
})
->addColumn('reference', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->getLastShoppingPayment('reference');
@ -101,10 +263,11 @@ class SalesController extends Controller
})
->orderColumn('id', 'id $1')
->orderColumn('txaction', 'txaction $1')
->orderColumn('payment_for', 'payment_for $1')
->orderColumn('shipped', 'shipped $1')
->orderColumn('total_shipping', 'total_shipping $1')
->rawColumns(['id', 'txaction', 'is_for', 'shipped'])
->rawColumns(['id', 'txaction', 'payment_for', 'shipped'])
->make(true);
}
@ -113,7 +276,7 @@ class SalesController extends Controller
if(Request::get('reset') === 'filter'){
set_user_attr('filter_txaction', null);
set_user_attr('filter_member_id', null);
return redirect(route('admin_sales_customers'));
return redirect(route('admin_sales'));
}
$filter_members = ShoppingOrder::join('users', 'member_id', '=', 'users.id')->groupBy('member_id')->join('user_accounts', 'account_id', '=', 'user_accounts.id')->select('users.id', 'users.email', 'user_accounts.first_name', 'user_accounts.last_name')->get(); //->pluck('email', 'id')->unique()->toArray();
$data = [
@ -149,7 +312,7 @@ class SalesController extends Controller
$shopping_order = ShoppingOrder::findOrFail($data['id']);
CustomerPriority::newMemberForOrder($shopping_order, $data['change_member_id'], $data['customer_set_member_for']);
\Session()->flash('alert-save', true);
return redirect(route('admin_sales_customers_detail', [$shopping_order->id]));
return redirect(route('admin_sales_detail', [$shopping_order->id]));
}
}
if($data['action']==='shopping-user-is-like-member'){
@ -177,7 +340,7 @@ class SalesController extends Controller
'isAdmin' => true,
'isView' => 'sales_customer',
];
return view('admin.sales.customer_detail', $data);
return view('admin.sales._detail', $data);
}
public function customersDatatable(){
@ -200,7 +363,7 @@ class SalesController extends Controller
return \DataTables::eloquent($query)
->addColumn('id', function (ShoppingOrder $ShoppingOrder) {
return '<a href="' . route('admin_sales_customers_detail', [$ShoppingOrder->id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
return '<a href="' . route('admin_sales_detail', [$ShoppingOrder->id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
})
->addColumn('created_at', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->created_at->format("d.m.Y");
@ -217,17 +380,8 @@ class SalesController extends Controller
->addColumn('shipped', function (ShoppingOrder $ShoppingOrder) {
return '<span class="badge badge-pill badge-'.$ShoppingOrder->getShippedColor().'">'.$ShoppingOrder->getShippedType().'</span>';
})
->addColumn('is_for', function (ShoppingOrder $ShoppingOrder) {
if($ShoppingOrder->shopping_user->is_for === 'me'){
return '<span class="badge badge-pill badge-secondary">Vertriebspartnerbestellung</span>';
}
if($ShoppingOrder->shopping_user->is_for === 'ot'){
return '<span class="badge badge-pill badge-info">Kundenbestellung</span>';
}
if($ShoppingOrder->shopping_user->is_for === 'hp'){
return '<span class="badge badge-pill badge-dark">Homepartybestellung</span>';
}
return '-';
->addColumn('payment_for', function (ShoppingOrder $ShoppingOrder) {
return Payment::getPaymentForTypeBadge($ShoppingOrder);
})
->addColumn('reference', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->getLastShoppingPayment('reference');
@ -240,7 +394,7 @@ class SalesController extends Controller
return '<button type="button" class="btn btn-xs btn-outline-info" data-toggle="modal" data-target="#modals-load-content"
data-id="'.$ShoppingOrder->shopping_user->id.'"
data-action="shopping-user-is-like-member"
data-back="'.route('admin_sales_customers').'"
data-back="'.route('admin_sales').'"
data-modal="modal-xl"
data-route="'.route('modal_load').'"><span class="fa fa-edit"></span> Vertriebspartner zuordnen</button>';
}
@ -249,130 +403,166 @@ class SalesController extends Controller
->orderColumn('id', 'id $1')
->orderColumn('txaction', 'txaction $1')
->orderColumn('payment_for', 'payment_for $1')
->orderColumn('member_id', 'member_id $1')
->orderColumn('shipped', 'shipped $1')
->orderColumn('total_shipping', 'total_shipping $1')
->rawColumns(['id', 'member_id', 'txaction', 'user_shop_id', 'is_for', 'shipped'])
->rawColumns(['id', 'member_id', 'txaction', 'user_shop_id', 'payment_for', 'shipped'])
->make(true);
}
}*/
public function store(){
public function store()
{
$data = Request::all();
if(!isset($data['id'])){
if (! isset($data['id'])) {
abort(404);
}
if(isset($data['action'])){
if($data['action'] === 'store_shipped' && isset($data['shipped'])){
if (isset($data['action'])) {
if ($data['action'] === 'store_shipped' && isset($data['shipped'])) {
$shopping_order = ShoppingOrder::findOrFail($data['id']);
$shopping_order->shipped = $data['shipped'];
$shopping_order->save();
// handel Promotion Product and credit by storno
Payment::handelUserPromotionOrder($shopping_order);
Payment::handelUserShopOrder($shopping_order);
if($shopping_order->getAPIShippedType() === 'sent' || $shopping_order->getAPIShippedType() === 'close'){
if(!$shopping_order->shipped_at){
if ($shopping_order->getAPIShippedType() === 'sent' || $shopping_order->getAPIShippedType() === 'close') {
if (! $shopping_order->shipped_at) {
$shopping_order->shipped_at = now();
$shopping_order->save();
//set to oder_margin
if($shopping_order->shopping_order_margin && $shopping_order->shopping_order_margin->hasPartnerCommission()){
$days = Setting::getContentBySlug('pending_partner_commissions_in_days');
$days = $days ? $days : 20;
$partner_commission_pending_to = $shopping_order->shipped_at;
$partner_commission_pending_to->addDays($days);
$shopping_order->shopping_order_margin->partner_commission_pending_to = $partner_commission_pending_to;
$shopping_order->shopping_order_margin->save();
// is shipped set pending_to
if ($shopping_order->shopping_order_margin) {
if ($shopping_order->shopping_order_margin->hasPartnerCommission()) {
$days = Setting::getContentBySlug('pending_partner_commissions_in_days');
$days = $days ? $days : 20;
$partner_commission_pending_to = $shopping_order->shipped_at;
$partner_commission_pending_to->addDays($days);
$shopping_order->shopping_order_margin->partner_commission_pending_to = $partner_commission_pending_to;
$shopping_order->shopping_order_margin->save();
} else {
$days = Setting::getContentBySlug('pending_order_margins_in_days');
$days = $days ? $days : 20;
$margin_pending_to = $shopping_order->shipped_at;
$margin_pending_to->addDays($days);
$shopping_order->shopping_order_margin->margin_pending_to = $margin_pending_to;
$shopping_order->shopping_order_margin->save();
}
}
}
}else{
} else {
$shopping_order->shipped_at = null;
$shopping_order->save();
if($shopping_order->shopping_order_margin && $shopping_order->shopping_order_margin->hasPartnerCommission()){
if ($shopping_order->shopping_order_margin) {
// zurücksetzen der pending_to
$shopping_order->shopping_order_margin->partner_commission_pending_to = null;
$shopping_order->shopping_order_margin->margin_pending_to = null;
$shopping_order->shopping_order_margin->save();
}
}
if($shopping_order->getAPIShippedType() === 'cancel'){
if($shopping_order->shopping_order_margin){
if ($shopping_order->getAPIShippedType() === 'cancel') {
if ($shopping_order->shopping_order_margin) {
$shopping_order->shopping_order_margin->cancellation = true;
$shopping_order->shopping_order_margin->partner_commission_pending_to = null;
$shopping_order->shopping_order_margin->margin_pending_to = null;
$shopping_order->shopping_order_margin->save();
}
}else{
if($shopping_order->shopping_order_margin && $shopping_order->shopping_order_margin->cancellation){
} else {
if ($shopping_order->shopping_order_margin && $shopping_order->shopping_order_margin->cancellation) {
$shopping_order->shopping_order_margin->cancellation = false;
$shopping_order->shopping_order_margin->partner_commission_pending_to = null;
$shopping_order->shopping_order_margin->margin_pending_to = null;
$shopping_order->shopping_order_margin->save();
}
}
}
if($data['action'] === 'store_txaction' && isset($data['txaction']) && isset($data['payment_id'])){
$shopping_order = ShoppingOrder::findOrFail($data['id']);
$shopping_payment = ShoppingPayment::findOrFail($data['payment_id']);
if($shopping_order->shopping_order_margin && $shopping_order->shopping_order_margin->from_payment_credit > 0){
$last_UserPayCredit = UserPayCredit::where('shopping_order_id', $shopping_order->id)->whereIn('status', [2, 4])->orderBy('id', 'DESC')->first();
//Status Keine Zahlung, Guthaben zurückführen, wenn status 2 / deduction from payment
if($last_UserPayCredit && $data['txaction'] === 'non' && $last_UserPayCredit->status === 2){
Payment::handelUserPayCredits($shopping_order, 'return');
}
//Status Zahlung, voher gab es eine Storno, Guthaben abziehen wenn status 4 / return from order
if($last_UserPayCredit && $last_UserPayCredit->status === 4 && ($data['txaction'] === 'open' || $data['txaction'] === 'paid')){
Payment::handelUserPayCredits($shopping_order, 'deduction');
}
}
$payt = PaymentTransaction::create([
'shopping_payment_id' => $shopping_payment->id,
'request' => 'transaction',
'txid' => 0,
'userid' => 0,
'status' => $shopping_payment->clearingtype,
'transmitted_data' => NULL,
'txaction' => $data['txaction'],
'mode' => $shopping_payment->mode,
]);
$shopping_order->txaction = $data['txaction'];
$shopping_order->paid = $payt->txaction === 'paid' ? true : false;
$shopping_order->save();
$shopping_payment->txaction = $data['txaction'];
$shopping_payment->save();
if($payt->status === 'vor' && $payt->txaction === 'paid'){
$send_link = Payment::paymentStatusPaidAction($shopping_order, true);
}
$edata = [
'mode' => $payt->mode,
'txaction' => $payt->txaction,
'send_link' => false,
];
//TODO can send MAIL
Payment::paymentStatusSendMail($shopping_order, $shopping_payment, $edata);
/* txaction ändern
änderung der txaction von der Bestellung, Status Zahlung, offen, bezahlt, keine zahlung */
if ($data['action'] === 'store_txaction' && isset($data['txaction']) && isset($data['payment_id'])) {
PaymentService::updateTransactionStatus($data['id'], $data['txaction'], $data['payment_id']);
}
}
if(isset($data['back'])){
if (isset($data['back'])) {
return redirect($data['back']);
}
return back();
}
public function invoice(){
public function invoice()
{
$data = Request::all();
//$data['id'] ShoppingOrder id
if(!isset($data['id'])){
if (! isset($data['id'])) {
abort(404);
}
if(isset($data['action'])){
if($data['action'] === 'create_invoice'){
if (isset($data['action'])) {
if ($data['action'] === 'create_invoice') {
$shopping_order = ShoppingOrder::findOrFail($data['id']);
$invoice_repo = new InvoiceRepository($shopping_order);
$invoice_repo->create($data);
return redirect(route('admin_sales_users_detail', [$shopping_order->id]));
if (Invoice::isInvoice($shopping_order)) {
$user_invoice = $invoice_repo->update($data);
} else {
$user_invoice = $invoice_repo->create($data);
}
return redirect(route('admin_sales_detail', [$shopping_order->id]));
}
}
}
public function invoiceCancellation()
{
$data = Request::all();
if (! isset($data['id'])) {
abort(404);
}
if (isset($data['action'])) {
if ($data['action'] === 'create_cancellation_invoice') {
$shopping_order = ShoppingOrder::findOrFail($data['id']);
// Prüfen ob bereits eine Rechnung existiert
if (! Invoice::isInvoice($shopping_order)) {
\Session()->flash('alert-error', 'Es existiert keine Rechnung, die storniert werden kann.');
return redirect(route('admin_sales_detail', [$shopping_order->id]));
}
// Prüfen ob bereits eine Stornorechnung existiert
if (Invoice::isCancellationInvoice($shopping_order)) {
\Session()->flash('alert-error', 'Es existiert bereits eine Stornorechnung für diese Bestellung.');
return redirect(route('admin_sales_detail', [$shopping_order->id]));
}
$invoice_repo = new InvoiceRepository($shopping_order);
$cancellation_invoice = $invoice_repo->createCancellation($data);
if ($cancellation_invoice) {
\Session()->flash('alert-success', 'Stornorechnung wurde erfolgreich erstellt.');
} else {
\Session()->flash('alert-error', 'Fehler beim Erstellen der Stornorechnung.');
}
return redirect(route('admin_sales_detail', [$shopping_order->id]));
}
}
return redirect(route('admin_sales'));
}
public function sendLogisticMail($id)
{
$shopping_order = ShoppingOrder::findOrFail($id);
if (Invoice::isInvoice($shopping_order)) {
Invoice::sendLogisticMail($shopping_order);
\Session()->flash('alert-success', 'Rechnung / Lieferschein wurde an den Versand gesendet.');
} else {
\Session()->flash('alert-error', 'Keine Rechnung vorhanden.');
}
return redirect(route('admin_sales_detail', [$shopping_order->id]));
}
}

View file

@ -24,7 +24,7 @@ class SettingController extends Controller
{
$data = [
'values' => Ingredient::all(),
'values' => [],
];
return view('admin.settings.index', $data);
}

View file

@ -0,0 +1,192 @@
<?php
namespace App\Http\Controllers\Stats;
use Auth;
use Request;
use App\User;
use Carbon\Carbon;
use Faker\Core\Number;
use App\Exports\ExcelExport;
use App\Services\HTMLHelper;
use App\Models\ShoppingOrder;
use App\Services\Stats\Sales;
use App\Models\ShoppingOrderItem;
use App\Http\Controllers\Controller;
use Maatwebsite\Excel\Facades\Excel;
use App\Services\BusinessPlan\ExportBot;
use Illuminate\Database\Eloquent\Collection;
class SalesController extends Controller
{
private $serviceSales;
public function __construct(Sales $serviceSales)
{
$this->middleware('admin');
$this->serviceSales = $serviceSales;
}
public function index()
{
$this->setFilterVars();
$data = [
'filter_months' => HTMLHelper::getTransMonths(true),
'filter_years' => HTMLHelper::getYearRange(2020),
'filter_products' => $this->serviceSales->setFilterProducts(),
];
return view('admin.stats.salesvolume', $data);
}
public function download()
{
$this->setFilterVars();
if (Request::get('action') === "filter") {
// $data = Request::all();
return back();
}
if (Request::get('action') === "export") {
$objects = $this->serviceSales->getObjects();
$columns = [];
$filename = "gs-absatzmengen-" . session('product_sales_vol_filter_month') . '_' . session('product_sales_vol_filter_year') . "-export";
$headers = array(
'#',
'Produkt',
'Artikelnummer',
'Menge',
'Gesamt Netto in EURO',
'Vorjahr Menge',
'Vorjahr Gesamt Netto in EURO',
'Einzelrabatt',
'Einzelrabatt %',
'VP Einzelrabatt %',
);
if ($objects) {
foreach ($objects as $key => $obj) {
$columns[] = array(
'id' => $key,
'name' => $obj['name'],
'number' => $obj['number'],
'qty' => $obj['qty'],
'total' => $obj['total'],
'pre_qty' => $obj['pre_qty'],
'pre_total' => $obj['pre_total'],
'single_commission' => $obj['single_commission'],
'value_commission' => $obj['value_commission'],
'partner_commission' => $obj['partner_commission'],
);
}
}
return Excel::download(new ExcelExport($columns, $headers), $filename . '.xls');
}
}
private function setFilterVars()
{
if (!session('product_sales_vol_filter_month')) {
session(['product_sales_vol_filter_month' => intval(date('m'))]);
}
if (!session('product_sales_vol_filter_year')) {
session(['product_sales_vol_filter_year' => intval(date('Y'))]);
}
if (!session('product_sales_vol_filter_products')) {
session(['product_sales_vol_filter_products' => []]);
}
if (Request::get('product_sales_vol_filter_month')) {
session(['product_sales_vol_filter_month' => Request::get('product_sales_vol_filter_month')]);
}
if (Request::get('product_sales_vol_filter_year')) {
session(['product_sales_vol_filter_year' => Request::get('product_sales_vol_filter_year')]);
}
if (Request::get('product_sales_vol_filter_products')) {
session(['product_sales_vol_filter_products' => Request::get('product_sales_vol_filter_products')]);
}
$this->serviceSales->setFilterVars(
session('product_sales_vol_filter_month'),
session('product_sales_vol_filter_year'),
session('product_sales_vol_filter_products')
);
}
public function datatable()
{
$this->setFilterVars();
$collection = $this->serviceSales->getCollection();
/* $collect = collect([
['id' => 1, 'name' => 'John', 'number'=>92012, 'value'=>123],
['id' => 2, 'name' => 'Jane', 'number'=>92012, 'value'=>123],
['id' => 3, 'name' => 'James', 'number'=>92012, 'value'=>123],
]);
*/
return \DataTables::of($collection)->toJson();
}
/*private function testCheckFunction(){
//$date_start = Carbon::parse('01.'.session('product_sales_vol_filter_month').'.'.session('product_sales_vol_filter_year'))->format('Y-m-d');
//$date_end = Carbon::parse('01.'.session('product_sales_vol_filter_month').'.'.session('product_sales_vol_filter_year'))->endOfMonth()->format('Y-m-d');
$date_start = Carbon::parse('01.01.2024')->format('Y-m-d H:i:s');
$date_end = Carbon::parse('01.01.2024')->endOfMonth()->format('Y-m-d H:i:s');
dump($date_start);
dump($date_end);
$ShoppingOrders = ShoppingOrder::where('mode', 'live')->whereBetween('created_at', [$date_start, $date_end])->get();
$objects = [];
$counter = 0;
foreach($ShoppingOrders as $ShoppingOrder){
foreach($ShoppingOrder->shopping_order_items as $shopping_order_item){
if($shopping_order_item->product){
if($shopping_order_item->product->id === 122){
//dump($shopping_order_item->qty);
//$counter += $shopping_order_item->qty;
if(isset($objects[$shopping_order_item->product->id])){
$value = intval($objects[$shopping_order_item->product->id]['value'] + $shopping_order_item->qty);
$objects[$shopping_order_item->product->id]['value'] = $value;
}else{
$objects[$shopping_order_item->product->id] = [
'name' => $shopping_order_item->product->name,
'number' => $shopping_order_item->product->number,
'value' => $shopping_order_item->qty
];
}
}
}
}
}
$ShoppingOrderItems = ShoppingOrderItem::whereProductId(122)->whereBetween('created_at', [$date_start, $date_end])->get();
$counter = 0;
foreach($ShoppingOrderItems as $ShoppingOrderItem){
$counter += $ShoppingOrderItem->qty;
dump($ShoppingOrderItem->id);
}
// dump($objects);
dump($counter);
dd("OKAY");
}*/
}

View file

@ -35,10 +35,9 @@ class AdminToolsController extends Controller
public function index($action)
{
dd($action);
switch ($action) {
case 'pay_credits':
# code...
dd($action);
$value = $this->makeUserPayCredits();
$data = [
'values' => $value,
@ -46,9 +45,28 @@ class AdminToolsController extends Controller
];
return view('sys.admin.index', $data);
break;
case 'value':
# code...
case 'export_vp':
$values = User::with('account')->select('users.*')->where('users.deleted_at', '=', null)->where('users.admin', "<", 4)->get();
$data = [
'values' => $values,
'text' => '',
];
return view('sys.admin.export_vp', $data);
break;
case 'dbaction':
$values = [];
$data = [
'values' => $values,
//'text' => 'Add payment_for in shopping_order', //_dbOrderPaymentFor
//'text' => 'Calculate TAX for shopping_order in tax_split array ',
'text' => 'show in AdminToolsController dbaction',
];
return view('sys.admin.index', $data);
break;
}
@ -58,22 +76,75 @@ class AdminToolsController extends Controller
public function store($action)
{
dd($action);
$data = [];
switch ($action) {
case 'pay_credits':
# code...
dd($action);
return view('sys.admin.index', $data);
break;
case 'export_vp':
return $this->export_vp();
break;
case 'dbaction':
//return $this->_dbOrderPaymentFor();
break;
break;
case 'value':
# code...
break;
}
}
private function _dbOrderPaymentFor(){
$c = 0;
$ShoppingUsers = ShoppingUser::all();
foreach($ShoppingUsers as $ShoppingUser){
if($ShoppingUser->shopping_order){
$ShoppingUser->shopping_order->payment_for = $ShoppingUser->getOrderPaymentFor();
$ShoppingUser->shopping_order->save();
$c ++;
}
}
dd($c);
}
private function export_vp(){
$query = User::with('account')->select('users.*')->where('users.deleted_at', '=', null)->where('users.admin', "<", 4)->get();
$fileName = "GS-VP-export-".date("d-m-Y").".csv";
$headers = array(
"Content-type" => "text/csv",
"Content-Disposition" => "attachment; filename=$fileName",
"Pragma" => "no-cache",
"Cache-Control" => "must-revalidate, post-check=0, pre-check=0",
"Expires" => "0"
);
$columns = array('ID', 'Email', 'Firma', 'Anrede', 'Vorname', 'Nachname', 'Mitglied', 'Bis');
$callback = function() use($query, $columns) {
$file = fopen('php://output', 'w');
fputcsv($file, $columns);
$row = [];
foreach ($query as $val) {
$row['ID'] = $val->id;
$row['Email'] = $val->email;
$row['Firma'] = $val->account->company;
$row['Anrede'] = $val->account->salutation == 'mr' ? 'Herr' : 'Frau' ;
$row['Vorname'] = $val->account->first_name;
$row['Nachname'] = $val->account->last_name;
$row['Mitglied'] = $val->payment_account ? ($val->isActiveAccount() ? 'JA' : 'Abgelaufen') : "Nein";
$row['Bis'] = $val->payment_account ? $val->getPaymentAccountDateFormat(false) : "-";
fputcsv($file, $row);
}
fclose($file);
};
return response()->stream($callback, 200, $headers);
//dd("ok");
}
private function makeUserPayCredits()
{
//is the first of
@ -214,7 +285,7 @@ class AdminToolsController extends Controller
$text = "";
$kas = new KasController();
$domain = 'mivita.care';
$domain = 'hier die DOMAIN';
$ssl = KasSLLController::getApiSSLParameter();

View file

@ -106,7 +106,6 @@ class CheckoutController extends Controller
$shopping_user->billing_state = Shop::getCountryShippingCountryId($shopping_user->billing_country_id);
$shopping_user->shipping_state = Shop::getCountryShippingCountryId($shopping_user->shipping_country_id);
$shopping_user->same_as_billing = $shopping_user->same_as_billing ? false : true; //reinvert
}
if($shopping_user->same_as_billing === NULL){
$shopping_user->same_as_billing = false;
@ -410,7 +409,7 @@ class CheckoutController extends Controller
'shopping_user_id' => $shopping_user->id,
'auth_user_id' => $shopping_user->auth_user_id,
'country_id' => Yard::instance('shopping')->getShippingCountryId(),
'payment_for' => Util::getUserPaymentFor(),
'payment_for' => $shopping_user->getOrderPaymentFor(),
'total' => Yard::instance('shopping')->total(2, '.', ''),
'subtotal_full' => Yard::instance('shopping')->subtotal(2, '.', '', false),
'discount' => $discount,
@ -499,11 +498,16 @@ class CheckoutController extends Controller
'net_amount' => Yard::instance('shopping')->getYardMargin()->net_amount,
'from_payment_credit' => Yard::instance('shopping')->totalfromCredit(2, '.', ''),
'from' => now(),
'status' => $shopping_order->payment_for, //7 => 'from promotion', 8 => 'from shop',
'content' => serialize(Yard::instance('shopping')->getYardMargin()->toArray())
];
if(Yard::instance('shopping')->getYardMargin()->net_partner_commission > 0){
$data['m_sponsor_id'] = $shopping_order->auth_user->m_sponsor;
$data['net_partner_commission'] = Yard::instance('shopping')->getYardMargin()->net_partner_commission;
if(isset($shopping_order->auth_user->m_sponsor)){
if($shopping_order->auth_user->user_sponsor && $shopping_order->auth_user->user_sponsor->isActiveAccount()){
$data['m_sponsor_id'] = $shopping_order->auth_user->m_sponsor;
$data['net_partner_commission'] = Yard::instance('shopping')->getYardMargin()->net_partner_commission;
}
}
}
$shopping_order_margin = false;
if ($this->getPayments('shopping_order_margin_id')) {
@ -518,6 +522,7 @@ class CheckoutController extends Controller
$this->putPayments('shopping_order_margin_id', $shopping_order_margin->id);
}
}
private function putPayments($key, $value){
$content = $this->getContent();
$content->put($key, $value);
@ -581,8 +586,6 @@ class CheckoutController extends Controller
];
Payment::paymentStatusSendMail($shopping_order, $shopping_payment, $data);
}
}
}

View file

@ -370,7 +370,11 @@ class HomepartyController extends Controller
$date = date('d.m.Y H:i:s', $time);
$user = User::find(Auth::user()->id);
Yard::instance('shopping')->destroy();
Yard::instance('shopping')->add($homeparty->id, 'Bestellung Homeparty '.$date, 1, \App\Services\HomepartyCart::$price, ['image' => "", 'slug' => $time, 'weight' => 0]);
die("STOP nicht getestet");
Yard::instance('shopping')->add($homeparty->id, 'Bestellung Homeparty '.$date, 1, \App\Services\HomepartyCart::$price, /*need TAX*/ 1, ['image' => "", 'slug' => $time, 'weight' => 0]);
// $cartItem = Yard::instance('shopping')->add($homeparty->id, 'Bestellung Homeparty '.$date, 1, \App\Services\HomepartyCart::$ek_price, false, false, ['image' => "", 'slug' => $time, 'weight' => 0]);
Yard::setTax($cartItem->rowId, 0);
do {
$identifier = Util::getToken();
} while( ShoppingInstance::where('identifier', $identifier)->count() );

View file

@ -0,0 +1,94 @@
<?php
namespace App\Http\Controllers\User;
use Auth;
use Yard;
use Request;
use App\User;
use Validator;
use App\Services\Util;
use App\Models\Product;
use App\Models\UserShop;
use App\Services\Payment;
use App\Models\UserHistory;
use App\Models\ShoppingUser;
use App\Models\ShoppingOrder;
use App\Models\ProductCategory;
use App\Models\ShippingCountry;
use App\Models\ShoppingInstance;
use App\Http\Controllers\Controller;
use App\Models\ProductBuy;
class MyOrderController extends Controller
{
public function __construct()
{
$this->middleware('active.account');
}
public function index()
{
$data = [
];
return view('user.order.index', $data);
}
public function detail($id)
{
$user = User::find(\Auth::user()->id);
$shopping_order = ShoppingOrder::findOrFail($id);
if($shopping_order->auth_user_id !== $user->id){
abort(404);
}
$shopping_order->getLastShoppingPayment();
$data = [
'shopping_order' => $shopping_order,
'isAdmin' => false,
];
return view('user.order.detail', $data);
}
public function datatable(){
$user = User::find(\Auth::user()->id);
$query = ShoppingOrder::with('shopping_user', 'shopping_payments')->select('shopping_orders.*')->where('auth_user_id', '=', $user->id)->where('txaction', '!=', NULL);
return \DataTables::eloquent($query)
->addColumn('id', function (ShoppingOrder $ShoppingOrder) {
return '<a href="' . route('user_myorder_detail', [$ShoppingOrder->id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
})
->addColumn('created_at', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->created_at->format("d.m.Y");
})
->addColumn('txaction', function (ShoppingOrder $ShoppingOrder) {
return Payment::getShoppingOrderBadge($ShoppingOrder);
})
->addColumn('total_shipping', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->getFormattedTotalShipping()."";
})
->addColumn('payment', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->getLastShoppingPayment('getPaymentType');
})
->addColumn('shipped', function (ShoppingOrder $ShoppingOrder) {
return '<span class="badge badge-pill badge-'.$ShoppingOrder->getShippedColor().'">'.$ShoppingOrder->getShippedType().'</span>';
})
->addColumn('payment_for', function (ShoppingOrder $ShoppingOrder) {
return Payment::getPaymentForTypeBadge($ShoppingOrder);
})
->addColumn('reference', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->getLastShoppingPayment('reference');
})
->orderColumn('id', 'id $1')
->orderColumn('txaction', 'txaction $1')
->orderColumn('payment_for', 'payment_for $1')
->orderColumn('shipped', 'shipped $1')
->orderColumn('total_shipping', 'total_shipping $1')
->rawColumns(['id', 'txaction', 'payment_for', 'shipped'])
->make(true);
}
}

View file

@ -7,18 +7,20 @@ use Yard;
use Request;
use App\User;
use Validator;
use App\Services\Shop;
use App\Services\Util;
use App\Models\Product;
use App\Models\UserShop;
use App\Services\Payment;
use App\Models\ProductBuy;
use App\Models\UserHistory;
use App\Models\ShoppingUser;
use App\Models\ShoppingOrder;
use App\Services\UserService;
use App\Models\ProductCategory;
use App\Models\ShippingCountry;
use App\Models\ShoppingInstance;
use App\Http\Controllers\Controller;
use App\Models\ProductBuy;
class OrderController extends Controller
{
@ -28,88 +30,15 @@ class OrderController extends Controller
$this->middleware('active.account');
}
public function index()
{
$data = [
];
return view('user.order.index', $data);
}
public function detail($id)
{
$user = User::find(\Auth::user()->id);
$shopping_order = ShoppingOrder::findOrFail($id);
if($shopping_order->auth_user_id !== $user->id){
abort(404);
}
$shopping_order->getLastShoppingPayment();
$data = [
'shopping_order' => $shopping_order,
'isAdmin' => false,
];
return view('user.order.detail', $data);
}
public function ordersDatatable(){
$user = User::find(\Auth::user()->id);
$query = ShoppingOrder::with('shopping_user', 'shopping_payments')->select('shopping_orders.*')->where('auth_user_id', '=', $user->id)->where('txaction', '!=', NULL);
return \DataTables::eloquent($query)
->addColumn('id', function (ShoppingOrder $ShoppingOrder) {
return '<a href="' . route('user_order_detail', [$ShoppingOrder->id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
})
->addColumn('created_at', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->created_at->format("d.m.Y");
})
->addColumn('txaction', function (ShoppingOrder $ShoppingOrder) {
return Payment::getShoppingOrderBadge($ShoppingOrder);
})
->addColumn('total_shipping', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->getFormattedTotalShipping()."";
})
->addColumn('payment', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->getLastShoppingPayment('getPaymentType');
})
->addColumn('shipped', function (ShoppingOrder $ShoppingOrder) {
return '<span class="badge badge-pill badge-'.$ShoppingOrder->getShippedColor().'">'.$ShoppingOrder->getShippedType().'</span>';
})
->addColumn('is_for', function (ShoppingOrder $ShoppingOrder) {
if($ShoppingOrder->shopping_user->is_for === 'me'){
return '<span class="badge badge-pill badge-secondary">Vertriebspartnerbestellung</span>';
}
if($ShoppingOrder->shopping_user->is_for === 'ot'){
return '<span class="badge badge-pill badge-info">Kundenbestellung</span>';
}
if($ShoppingOrder->shopping_user->is_for === 'hp'){
return '<span class="badge badge-pill badge-dark">Homepartybestellung</span>';
}
return '-';
})
->addColumn('reference', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->getLastShoppingPayment('reference');
})
->orderColumn('id', 'id $1')
->orderColumn('txaction', 'txaction $1')
->orderColumn('shipped', 'shipped $1')
->orderColumn('total_shipping', 'total_shipping $1')
->rawColumns(['id', 'txaction', 'is_for', 'shipped'])
->make(true);
}
public function delivery($for, $id=null)
{
$user = User::find(\Auth::user()->id);
$shopping_user = null;
$delivery_id = null;
if($for === 'ot'){
$shopping_user = $this->checkShoppingUser($id, $user);
if(strpos($for, 'ot') !== false){
$shopping_user = Shop::checkShoppingUser($id, $user);
$delivery_id = $shopping_user->id;
if(!$this->checkShoppingCountry($for, $delivery_id) && !\Session()->has('custom-error')){
if(!Shop::checkShoppingCountry($for, $delivery_id) && !\Session()->has('custom-error')){
\Session()->flash('custom-error', __('validation.custom.shipping_not_found'));
return redirect(route('user_order_my_delivery', [$for, $delivery_id]));
}
@ -117,12 +46,11 @@ class OrderController extends Controller
if(Request::get('action') === 'next'){
Yard::instance('shopping')->destroy();
if(Request::get('switchers-radio-is-for') === 'ot'){
if(strpos(Request::get('switchers-radio-is-for'), 'ot') !== false){
$delivery_id = $id;
}
return redirect(route('user_order_my_list', [Request::get('switchers-radio-is-for'), $delivery_id]));
}
$data = [
'shopping_user' => $shopping_user,
'isAdmin' => false,
@ -140,19 +68,31 @@ class OrderController extends Controller
$shopping_user = null;
$delivery_id = null;
if($for === 'ot'){
$shopping_user = $this->checkShoppingUser($id, $user);
if(strpos($for, 'ot') !== false){
$shopping_user = Shop::checkShoppingUser($id, $user);
$delivery_id = $shopping_user->id;
}
$shipping_country_id = $this->checkShoppingCountry($for, $id);
if(!$shipping_country_id){
\Session()->flash('custom-error', __('validation.custom.shipping_not_found'));
return redirect(route('user_order_my_delivery', [$for, $delivery_id]));
if($for === 'ot-customer'){ //noch nicht implementiert
//Liederung an ot-customer (Kunden) Zahlung und Rechnung geht an Kunden
UserService::initCustomerYard($shopping_user, $for);
}else{
//Lieferung an user oder ot-member (Kunden) rechnung geht an User
//lieferland und rechnungsland prüfen
$shipping_country_id = Shop::checkShoppingCountry($for, $id);
if(!$shipping_country_id){
\Session()->flash('custom-error', __('validation.custom.shipping_not_found'));
return redirect(route('user_order_my_delivery', [$for, $delivery_id]));
}
UserService::initUserYard($user, $shipping_country_id, $for);
}
Yard::instance('shopping')->setShippingCountryWithPrice($shipping_country_id, $for);
Yard::instance('shopping')->setShoppingUser($user, true);
if($for === 'cr'){
Yard::instance('shopping')->setGlobalTaxRate(0);
Yard::instance('shopping')->setShoppingUser($user, false);
}else{
Yard::instance('shopping')->setShoppingUser($user, true);
}
$data = [
'shopping_user' => $shopping_user,
'user' => $user,
@ -166,24 +106,29 @@ class OrderController extends Controller
}
public function payment($for, $id=null){
$data = Request::all();
$user = User::find(Auth::user()->id);
$rules = array(
'shipping_salutation' => 'required',
'shipping_firstname'=>'required',
'shipping_lastname'=>'required',
'shipping_address'=>'required',
'shipping_zipcode'=>'required',
'shipping_firstname' => 'required',
'shipping_lastname' => 'required',
'shipping_address' => 'required',
'shipping_zipcode' => 'required',
'shipping_city' => 'required',
'shipping_state' => 'required',
);
$validator = Validator::make(Request::all(), $rules);
if ($validator->fails()) {
return back()->withErrors($validator)->withInput(Request::all());
}
//hier prüfen, ob versand etc richtig berechnet wurde
$this->checkSendYardForPayment($data, $id);
if(Yard::instance('shopping')->getNumComp() > 0){
if(Yard::instance('shopping')->getNumComp() > 0){
if(!isset($data['switchers-comp-product'])){
$validator->errors()->add('switchers-comp-product', __('Bitte wähle ein Kompensationsprodukt aus'));
}else{
@ -200,13 +145,17 @@ class OrderController extends Controller
}
}
/*do {
/*
do {
$identifier = Util::getToken();
} while( ShoppingInstance::where('identifier', $identifier)->count() );*/
} while( ShoppingInstance::where('identifier', $identifier)->count() );
*/
$identifier = Util::getToken();
$data['is_from'] = 'user_order';
$data['is_for'] = $for;
$data['shopping_user_id'] = $id;
$data['user_price_infos'] = Yard::instance('shopping')->getUserPriceInfos();
unset($data['quantity']);
unset($data['_token']);
@ -221,7 +170,6 @@ class OrderController extends Controller
'country_id' => Yard::instance('shopping')->getShippingCountryId(),
'shopping_data' => $data,
'back' => url()->previous(),
]);
Yard::instance('shopping')->store($identifier);
*/
@ -233,58 +181,129 @@ class OrderController extends Controller
return redirect(route('user_checkout', [$identifier]));
}
private function checkShoppingCountry($for, $id=null){
$country_id = null;
if($for === 'me'){
$user = User::find(\Auth::user()->id);
if($user->same_as_billing){
$country_id = $user->account->country_id;
}else{
$country_id = $user->account->shipping_country_id;
}
private function checkSendYardForPayment($data, $id){
$user = User::find(\Auth::user()->id);
$shopping_user = null;
if(strpos($data['shipping_is_for'], 'ot') !== false){
$shopping_user = Shop::checkShoppingUser($id, $user);
}
if($for === 'ot' && $id){
$shopping_user = ShoppingUser::findOrFail($id);
if($shopping_user->same_as_billing){
$country_id = $shopping_user->billing_country_id;
}else{
$country_id = $shopping_user->shipping_country_id;
$shipping_country_id = Shop::checkShoppingCountry($data['shipping_is_for'], $id);
if(!$shipping_country_id){
$identifier = 'error-'.time().mt_rand(1000000, 9999999);
Yard::instance('shopping')->store($identifier);
$data['user_id'] = Auth::user()->id;
$data['shopping_user_id'] = $id;
\App\Services\MyLog::writeLog('payment', 'error', 'no shipping_country_id found | Yard identifier: '.$identifier, $data);
abort(403, __('msg.shipping_country_was_not_found'));
}
//must be the same shipping country
if($shipping_country_id != Yard::instance('shopping')->getShippingCountryId()){
$identifier = 'error-'.time().mt_rand(1000000, 9999999);
Yard::instance('shopping')->store($identifier);
$data['user_id'] = Auth::user()->id;
$data['shopping_user_id'] = $id;
\App\Services\MyLog::writeLog('payment', 'error', 'shipping_country_id is not the same from Yard | Yard identifier: '.$identifier, $data);
abort(403, __('msg.shipping_country_was_not_correctly'));
}
if($data['shipping_is_for'] !== 'ot-customer'){
if(Yard::instance('shopping')->shipping_free){
$identifier = 'error-'.time().mt_rand(1000000, 9999999);
Yard::instance('shopping')->store($identifier);
$data['user_id'] = Auth::user()->id;
$data['shopping_user_id'] = $id;
\App\Services\MyLog::writeLog('payment', 'error', 'Yard can by not shipping_free | Yard identifier: '.$identifier, $data);
abort(403, __('msg.shopping_cart_was_shipping_free'));
}
}
if($country_id){
if($shipping_country = ShippingCountry::whereCountryId($country_id)->first()){
return $shipping_country->id;
if($data['shipping_is_for'] === 'ot-customer'){
if(!$user->shop){
$identifier = 'error-'.time().mt_rand(1000000, 9999999);
Yard::instance('shopping')->store($identifier);
$data['user_id'] = Auth::user()->id;
$data['shopping_user_id'] = $id;
\App\Services\MyLog::writeLog('payment', 'error', 'User has no Shop for an User to Customer order| Yard identifier: '.$identifier, $data);
abort(403, __('msg.shopping_cart_was_not_user_shop'));
}
}
return false;
$shipping_price = Shop::getShippingPriceByShippingCountryId($shipping_country_id, Yard::instance('shopping')->weight());
//for other and has weight - check
if(strpos($data['shipping_is_for'], 'ot') !== false && $data['shipping_is_for'] !== 'ot-customer' && Yard::instance('shopping')->weight() > 0){
if(!Yard::instance('shopping')->getShippingPrice() || Yard::instance('shopping')->getShippingPrice() == 0){
$identifier = 'error-'.time().mt_rand(1000000, 9999999);
Yard::instance('shopping')->store($identifier);
$data['user_id'] = Auth::user()->id;
$data['shopping_user_id'] = $id;
\App\Services\MyLog::writeLog('payment', 'error', 'Yard OT shipping_price is 0 or | Yard identifier: '.$identifier, $data);
abort(403, __('msg.shipping_cost_cannot_be_0'));
}
if(Yard::instance('shopping')->getShippingPrice() != $shipping_price->price){
$identifier = 'error-'.time().mt_rand(1000000, 9999999);
Yard::instance('shopping')->store($identifier);
$data['user_id'] = Auth::user()->id;
$data['shopping_user_id'] = $id;
\App\Services\MyLog::writeLog('payment', 'error', 'Yard OT shipping_price is not the same from shipping_price | Yard identifier: '.$identifier, $data);
abort(403, __('msg.shipping_costs_were_not_calculated_correctly'));
}
}
if($data['shipping_is_for'] == 'me' && Yard::instance('shopping')->weight() > 0){
if(!Yard::instance('shopping')->getShippingPrice() || Yard::instance('shopping')->getShippingPrice() == 0){
$identifier = 'error-'.time().mt_rand(1000000, 9999999);
Yard::instance('shopping')->store($identifier);
$data['user_id'] = Auth::user()->id;
$data['shopping_user_id'] = $id;
\App\Services\MyLog::writeLog('payment', 'error', 'Yard ME shipping_price is 0 or | Yard identifier: '.$identifier, $data);
abort(403, __('msg.shipping_cost_cannot_be_0'));
}
if(Yard::instance('shopping')->getShippingPrice() != $shipping_price->price_comp){
$identifier = 'error-'.time().mt_rand(1000000, 9999999);
Yard::instance('shopping')->store($identifier);
$data['user_id'] = Auth::user()->id;
$data['shopping_user_id'] = $id;
\App\Services\MyLog::writeLog('payment', 'error', 'Yard ME shipping_price is not the same from shipping_price | Yard identifier: '.$identifier, $data);
abort(403, __('msg.shipping_costs_were_not_calculated_correctly'));
}
if(Yard::instance('shopping')->getNumComp() != $shipping_price->num_comp){
$identifier = 'error-'.time().mt_rand(1000000, 9999999);
Yard::instance('shopping')->store($identifier);
$data['user_id'] = Auth::user()->id;
$data['shopping_user_id'] = $id;
\App\Services\MyLog::writeLog('payment', 'error', 'Yard num_comp is 0 | Yard identifier: '.$identifier, $data);
abort(403, __('msg.compensation_products_cannot_be_0'));
}
}
}
private function checkShoppingUser($id, $user){
if($id === null){
abort(403, 'Error: Keine User ID');
}
$shopping_user = ShoppingUser::findOrFail($id);
if($shopping_user->member_id !== $user->id){
abort(403, 'Error: Falsche User ID');
}
$shopping_user = ShoppingUser::findOrFail($id);
if($shopping_user->is_like){
abort(403, 'Error: Kunde in Prüfung');
}
return $shopping_user;
}
public function datatable(){
$not_show_pids = ProductBuy::getNotShowProductIDs(Auth::user()->id);
if(Request::get('shipping_is_for') === 'me'){
$query = Product::select('products.*')->where('active', true)->whereJsonContains('show_on', '2');
}else{
$query = Product::select('products.*')->where('active', true)->whereJsonContains('show_on', '1');
switch (Request::get('shipping_is_for')) {
case 'me':
$query = Product::select('products.*')->where('active', true)->whereJsonContains('show_on', '2');
break;
case 'mp':
$query = Product::select('products.*')->where('active', true)->whereJsonContains('show_on', '2');
break;
case 'cr':
$query = Product::select('products.*')->where('active', true)->whereJsonContains('show_on', '6');
break;
case 'ot':
$query = Product::select('products.*')->where('active', true)->whereJsonContains('show_on', '1');
break;
}
foreach($not_show_pids as $not_show_pid){
$query->where('id', '!=', $not_show_pid);
}
@ -292,7 +311,6 @@ class OrderController extends Controller
return \DataTables::eloquent($query)
->addColumn('product', function (Product $product) {
$cartItem = Yard::instance('shopping')->getCartItemByProduct($product->id);
$qty = isset($cartItem->qty) ? $cartItem->qty : 0;
$rowId = isset($cartItem->rowId) ? $cartItem->rowId : '';
@ -309,7 +327,6 @@ class OrderController extends Controller
</div>';
})
/*
->addColumn('add_card', function (Product $product) {
return '<button type="button" class="btn btn-sm btn-md-extra btn-secondary add-product-basket" data-product-id="'.$product->id.'">
<strong>&euro; '.$product->getFormattedPriceWith().'</strong>&nbsp; +<span class="ion ion-md-cart"></span>
@ -418,7 +435,11 @@ class OrderController extends Controller
}
//get the card item
$cartItem = Yard::instance('shopping')->add($product->id, $product->getLang('name'), 1, $product->getPriceWith(false, true), $product->tax,
//Yard::instance('shopping')->add($product->id, $product->getLang('name'), 1, $product->price, $product->tax, ['image' => $image, 'slug' => $product->slug, 'weight' => $product->weight]);
$cartItem = Yard::instance('shopping')->add($product->id, $product->getLang('name'), 1, $product->price, $product->tax,
//$product->getPriceWith(Yard::instance('shopping')->getUserTaxFree(), true, Yard::instance('shopping')->getUserCountry()), $product->getTaxWith(Yard::instance('shopping')->getUserCountry()), //$product->tax, true?
[
'image' => $image,
'slug' => $product->slug,
@ -428,7 +449,14 @@ class OrderController extends Controller
'value_commission' => $product->value_commission,
'partner_commission' => $product->partner_commission,
]);
Yard::setTax($cartItem->rowId, $product->tax);
if(Yard::instance('shopping')->getUserTaxFree()){
//Yard::setTax($cartItem->rowId, 0);
Yard::instance('shopping')->setGlobalTaxRate(0);
}else{
//Yard::setTax($cartItem->rowId, $product->getTaxWith(Yard::instance('shopping')->getUserCountry()));
}
if(isset($data['qty']) && $data['qty'] > 0){
Yard::instance('shopping')->update($cartItem->rowId, $data['qty']);
@ -446,6 +474,16 @@ class OrderController extends Controller
return response()->json(['response' => true, 'data'=>$data, 'html_card'=>$html_card, 'html_comp'=>$html_comp]);
}
}
if($data['action'] === 'reCalculateCart') {
//set use_payment_credit
$data['reduce_payment_credit'] = $data['reduce_payment_credit'] == 'true' ? true: false;
Yard::instance('shopping')->setReducePaymentCredit($data['reduce_payment_credit']);
Yard::instance('shopping')->reCalculate();
$html_card = view("user.order.yard_view_form", $data)->render();
$html_comp = view("user.order.comp_product", $data)->render();
return response()->json(['response' => true, 'data'=>$data, 'html_card'=>$html_card, 'html_comp'=>$html_comp]);
}
if($data['action'] === 'clearCart') {
Yard::instance('shopping')->destroy();
return response()->json(['response' => true, 'data'=>Yard::instance('shopping')->count(), 'html_card'=>'', 'html_comp'=>'']);
@ -454,7 +492,7 @@ class OrderController extends Controller
if($data['action'] === 'updateShippingCountry') {
if(isset($data['shipping_country_id'])){
if($shipping_country = ShippingCountry::find($data['shipping_country_id'])){
Yard::instance('shopping')->setShippingCountryWithPrice($shipping_country->id, $is_for);
Yard::instance('shopping')->setShippingCountryWithPrice($shipping_country->id, $is_for); //$is_for == 'ot' or 'me'
$this->checkCompProduct(Yard::instance('shopping')->getNumComp());
}
}
@ -498,37 +536,52 @@ class OrderController extends Controller
}
}
if(isset($data['comp_product_id'])) {
if ($product = Product::find($data['comp_product_id'])) {
$image = "";
if ($product->images->count()) {
$image = $product->images->first()->slug;
}
$cartItem = Yard::instance('shopping')->add($product->id, $product->getLang('name'), 1, 0, 0,
[
'image' => $image,
'slug' => $product->slug,
'weight' => 0,
'single_commission' => 0,
'amount_commission' => 0,
'value_commission' => 0,
'partner_commission' => 0,
'comp' => $data['comp_num'],
'product_id' => $product->id
]);
Yard::setTax($cartItem->rowId, 0);
if(isset($data['comp_product_id'])) {
if ($product = Product::find($data['comp_product_id'])) {
$image = "";
if ($product->images->count()) {
$image = $product->images->first()->slug;
}
$cartItem = Yard::instance('shopping')->add($product->id, $product->getLang('name'), 1, 0, 0,
[
'image' => $image,
'slug' => $product->slug,
'weight' => 0,
'single_commission' => 0,
'amount_commission' => 0,
'value_commission' => 0,
'partner_commission' => 0,
'comp' => $data['comp_num'],
'product_id' => $product->id
]);
Yard::setTax($cartItem->rowId, 0);
}
}
}
private function getCompProducts($for){
private function getCompProducts($for) {
if($for === 'me' && \App\Models\Setting::getContentBySlug('order_partner_is_comp_me')) {
return Product::whereActive(true)
->where(function($query) {
$query->whereRaw("JSON_CONTAINS(show_on, '\"2\"')")
->orWhereRaw("JSON_CONTAINS(show_on, '\"11\"')");
})
->where('shipping_addon', true)
->orderBy('pos', 'DESC')
->get();
}
if($for === 'me' && \App\Models\Setting::getContentBySlug('order_partner_is_comp_me')){
return Product::whereActive(true)->whereJsonContains('show_on', ['2'])->where('shipping_addon', true)->orderBy('pos', 'DESC')->get();
}
if($for === 'ot' && \App\Models\Setting::getContentBySlug('order_partner_is_comp_ot')){
return Product::whereActive(true)->whereJsonContains('show_on', ['1'])->where('shipping_addon', true)->orderBy('pos', 'DESC')->get();
if($for === 'ot' && \App\Models\Setting::getContentBySlug('order_partner_is_comp_ot')) {
return Product::whereActive(true)
->where(function($query) {
$query->whereRaw("JSON_CONTAINS(show_on, '\"1\"')")
->orWhereRaw("JSON_CONTAINS(show_on, '\"11\"')");
})
->where('shipping_addon', true)
->orderBy('pos', 'DESC')
->get();
}
return null;
}

View file

@ -45,10 +45,12 @@ class PaymentController extends Controller
->addColumn('message', function (UserPayCredit $user_pay_credit) {
if($user_pay_credit->status === 3){
return nl2br($user_pay_credit->message);
}elseif($user_pay_credit->status === 5 || $user_pay_credit->status === 6){
return trans('payment.'.$user_pay_credit->message).
' &nbsp; <a class="btn btn-outline-secondary btn-xs" href="'.route('user_sales_detail', [$user_pay_credit->shopping_order_id]).'"><i class="ion ion-md-eye"></i></a>';
}else{
return trans('payment.'.$user_pay_credit->message).
' &nbsp; <a class="btn btn-outline-secondary btn-xs" href="'.route('user_order_detail', [$user_pay_credit->shopping_order_id]).'"><i class="ion ion-md-eye"></i></a>';
' &nbsp; <a class="btn btn-outline-secondary btn-xs" href="'.route('user_myorder_detail', [$user_pay_credit->shopping_order_id]).'"><i class="ion ion-md-eye"></i></a>';
}
})
->addColumn('credit', function (UserPayCredit $user_pay_credit) {

View file

@ -3,15 +3,14 @@
namespace App\Http\Controllers\User;
use Request;
use Validator;
use App\Models\PromotionUser;
use App\Models\PromotionAdmin;
use App\Http\Controllers\Controller;
use Response;
use Illuminate\Support\Facades\Auth;
use App\Models\PromotionAdminProduct;
use App\Repositories\UserPromotionRepository;
use Validator;
use App\Services\Util;
use App\Models\PromotionUser;
use App\Services\UserService;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use App\Repositories\UserPromotionRepository;
class PromotionController extends Controller
{
@ -38,7 +37,10 @@ class PromotionController extends Controller
if($user_promotion->user_id != Auth::user()->id){
abort(404);
}
$user_promotion->about_you = !$user_promotion->about_you ? $user_promotion->user->account->about_you : $user_promotion->about_you;
$user_promotion->description = $user_promotion->description ? $user_promotion->description : $user_promotion->promotion_admin->user_description;
$about_you = $user_promotion->user->account->about_you ?$user_promotion->user->account->about_you : $user_promotion->promotion_admin->user_about;
$user_promotion->about_you = $user_promotion->about_you ? $user_promotion->about_you : $about_you;
$data = [
'checkPaymentCredit' => $user_promotion->checkPaymentCredit(),
'user_promotion_cart' => PromotionUser::preCalculateCart($user_promotion, 'user_promotion'),
@ -59,14 +61,21 @@ class PromotionController extends Controller
if(isset($data['action']) && $data['action'] === 'save-user-promotion'){
$rules = array(
'name' => 'required',
'user_promotion_url' => ' required|alpha_dash|profanity|unique:promotion_users,url,'.\Auth::user()->id.',user_id|min:4|max:20',
'user_promotion_url' => ' required|alpha_dash|'.'unique:promotion_users,url,'.$id.',id'.'|min:4|max:20|full_word_check',
);
Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
$profanity = \App\Models\Setting::getContentBySlug('promotion_user_url_profanity');
$profanity = array_map('trim', explode(',', $profanity));
if(in_array($value, $profanity)){
return false;
}
return true;
});
$validator = Validator::make(Request::all(), $rules);
if ($validator->fails()) {
return redirect(route('user_promotion_detail', [$id]))->withErrors($validator)->withInput(Request::all());
}
$model = $this->promoRepo->update($id, Request::all());
}
\Session()->flash('alert-save', true);
return redirect(route('user_promotion_detail', [$model->id]));
@ -91,19 +100,23 @@ class PromotionController extends Controller
public function load(){
$data = Request::all();
if(Request::ajax()) {
if(isset($data['action']) && $data['action'] === 'validate_url'){
$unique = 'unique:promotion_users,url';
if(isset($data['puid'])){
$unique .= ','.$data['puid'].',id';
}
$rules = array(
//'user_promotion_url' => ' required|alpha_dash|profanity|unique:user_shops,name|min:4|max:20|full_word_check',
'user_promotion_url' => ' required|alpha_dash|profanity|unique:promotion_users,url,'.\Auth::user()->id.',user_id|min:4|max:20',
'user_promotion_url' => ' required|alpha_dash|'.$unique.'|min:4|max:20|full_word_check',
);
/*Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
if(in_array($value, config('profanity.full_word_check'))){
Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
$profanity = \App\Models\Setting::getContentBySlug('promotion_user_url_profanity');
$profanity = array_map('trim', explode(',', $profanity));
if(in_array($value, $profanity)){
return false;
}
return true;
});*/
});
$validator = Validator::make(Request::all(), $rules);
if ($validator->fails()) {

View file

@ -1,53 +0,0 @@
<?php
namespace App\Http\Controllers\User;
use App\Http\Controllers\Controller;
use App\User;
use Request;
use Carbon;
use App\Models\ShoppingOrder;
class RevenueController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
public function index()
{
$start = 2021;
$end = date('Y');
$years = range($start, $end);
if(Request::get('filter_sales_year')){
$active_year = Request::get('filter_sales_year');
}else{
$active_year = $end;
}
$date1 = Carbon::parse('01.01.'.$active_year." 00:00:00")->format('Y-m-d H:i:s');
$date2 = Carbon::parse('31.12.'.$active_year." 23:59:59")->toDateString();
$values = ShoppingOrder::where('shopping_orders.auth_user_id', '!=', NULL) //::with('shopping_user', )->select('shopping_orders.*')
->where('mode', '=', 'live')
->where('paid', '=', 1)
->whereHas('shopping_order_items', function($q) {
$q->where('product_id', 34)->OrWhere('product_id', 35)->OrWhere('product_id', 36)->OrWhere('product_id', 67)->OrWhere('product_id', 69);
})
->whereBetween('created_at', [$date1, $date2])
->get();
$data = [
'years' => $years,
'active_year' => $active_year,
'values' => $values,
];
return view('user.revenue.index', $data);
}
}

View file

@ -0,0 +1,92 @@
<?php
namespace App\Http\Controllers\User;
use App\Http\Controllers\Controller;
use App\Models\ShoppingOrder;
use App\Services\Payment;
use App\User;
class SalesController extends Controller
{
protected $userShopRepo;
public function __construct()
{
$this->middleware('active.account');
}
public function index()
{
$data = [
];
return view('user.sales.index', $data);
}
public function detail($id)
{
$user = User::find(\Auth::user()->id);
$shopping_order = ShoppingOrder::findOrFail($id);
if($shopping_order->member_id !== $user->id){
abort(404);
}
if($shopping_order->payment_for !== 6 && $shopping_order->payment_for !== 7 && $shopping_order->payment_for !== 8){
return redirect(route('user_myorder_detail', [$shopping_order->id]));
abort(403, 'Beraterbestellung');
}
$data = [
'shopping_order' => $shopping_order,
'isAdmin' => false,
];
return view('user.sales.detail', $data);
}
public function datatable(){
$user = User::find(\Auth::user()->id);
$query = ShoppingOrder::with('shopping_user')->select('shopping_orders.*')->where('shopping_orders.member_id', $user->id);
return \DataTables::eloquent($query)
->addColumn('id', function (ShoppingOrder $ShoppingOrder) {
return '<a href="' . route('user_sales_detail', [$ShoppingOrder->id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
})
->addColumn('created_at', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->created_at->format("d.m.Y");
})
->addColumn('txaction', function (ShoppingOrder $ShoppingOrder) {
return Payment::getShoppingOrderBadge($ShoppingOrder);
})
->addColumn('total_shipping', function (ShoppingOrder $ShoppingOrder) {
return '<span class="no-line-break">'.$ShoppingOrder->getFormattedTotalShipping()." €</span>";
})
->addColumn('orders', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->shopping_user ? $ShoppingOrder->shopping_user->orders : '';
})
->addColumn('user_shop_id', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->user_shop ? '<a href="'.$ShoppingOrder->user_shop->getSubdomain(false).'" target="_blank">'.$ShoppingOrder->user_shop->getSubdomain(false).'</span>' : '';
})
->addColumn('payment_for', function (ShoppingOrder $ShoppingOrder) {
return Payment::getPaymentForTypeBadge($ShoppingOrder);
})
->addColumn('shipped', function (ShoppingOrder $ShoppingOrder) {
return '<span class="badge badge-pill badge-'.$ShoppingOrder->getShippedColor().'">'.$ShoppingOrder->getShippedType().'</span>
';
})
->addColumn('invoice', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->isInvoice() ? '<span class="no-line-break"><a href="'.route('storage_file', [$ShoppingOrder->id, 'invoice', 'download']).'" class="btn btn-primary btn-xs"><i class="fa fa-download"></i></a>
<a href="'.route('storage_file', [$ShoppingOrder->id, 'invoice', 'stream']).'" target="_blank" class="btn btn-warning btn-xs"><i class="fa fa-eye"></i></a></span>' : '-';
})
->orderColumn('payment_for', 'payment_for $1')
->orderColumn('id', 'id $1')
->orderColumn('txaction', 'txaction $1')
->orderColumn('user_shop_id', 'user_shop_id $1')
->orderColumn('total_shipping', 'total_shipping $1')
->rawColumns(['id', 'txaction', 'user_shop_id', 'total_shipping', 'invoice', 'shipped', 'payment_for'])
->make(true);
}
}

View file

@ -0,0 +1,119 @@
<?php
namespace App\Http\Controllers\User;
use Request;
use App\User;
use Response;
use Validator;
use App\Services\Util;
use App\Models\UserShop;
use App\Models\PromotionUser;
use App\Services\UserService;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use App\Repositories\UserShopRepository;
class ShopController extends Controller
{
protected $userShopRepo;
public function __construct(UserShopRepository $userShopRepo)
{
$this->middleware('active.account');
$this->userShopRepo = $userShopRepo;
}
public function index(){
$user = Auth::user();
// $user_shop = UserShop::where('user_id', Auth::user()->id)->first();
if(!$user->shop){
//create new shop
$user = $this->createNewUserShop(Auth::user());
}
if($user->shop->user_id != Auth::user()->id){
abort(404);
}
$data = [
'user_shop' => $user->shop,
];
return view('user.shop.detail', $data);
}
private function createNewUserShop($user){
return $this->userShopRepo->create($user);
}
public function store()
{
$data = Request::all();
$user = Auth::user();
if(isset($data['action']) && $data['action'] === 'save-user-shop'){
$rules = array(
'name' => 'required',
'user_shop_url' => ' required|alpha_dash|'.'unique:user_shops,url,'.$user->shop->id.',id'.'|min:4|max:20|full_word_check',
);
Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
$profanity = \App\Models\Setting::getContentBySlug('promotion_user_url_profanity');
$profanity = array_map('trim', explode(',', $profanity));
if(in_array($value, $profanity)){
return false;
}
return true;
});
$validator = Validator::make(Request::all(), $rules);
if ($validator->fails()) {
return redirect(route('user_shop'))->withErrors($validator)->withInput(Request::all());
}
$model = $this->userShopRepo->update($user->shop->id, Request::all());
}
\Session()->flash('alert-save', true);
return redirect(route('user_shop'));
}
public function load(){
$data = Request::all();
if(Request::ajax()) {
if(isset($data['action']) && $data['action'] === 'validate_url'){
$unique = 'unique:user_shops,url';
if(isset($data['usid'])){
$unique .= ','.$data['usid'].',id';
}
$rules = array(
'user_shop_url' => ' required|alpha_dash|'.$unique.'|min:4|max:20|full_word_check',
);
Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
$profanity = \App\Models\Setting::getContentBySlug('promotion_user_url_profanity');
$profanity = array_map('trim', explode(',', $profanity));
if(in_array($value, $profanity)){
return false;
}
return true;
});
$validator = Validator::make(Request::all(), $rules);
if ($validator->fails()) {
//$messages = $validator->messages();
return Response::json(array(
'success' => false,
'errors' => $validator->getMessageBag()->toArray()
));
}
//$slug = SlugService::createSlug(UserShop::class, 'slug', Request::get('user_promotion_url'));
$name = Util::sanitize(Request::get('user_shop_url'), true, false, true, true);
return Response::json(array(
'success' => true,
'preview_user_shop_url' => config('app.shop_url')."/".$name,
));
}
}
}
}

View file

@ -1,74 +0,0 @@
<?php
namespace App\Http\Controllers\User;
use App\Http\Controllers\Controller;
use App\Models\ShoppingOrder;
use App\Services\Payment;
use App\User;
class ShopSalesController extends Controller
{
public function __construct()
{
$this->middleware('active.shop');
}
public function orders()
{
$data = [
];
return view('user.shop.sales.orders', $data);
}
public function orderDetail($id)
{
$user = User::find(\Auth::user()->id);
$shopping_order = ShoppingOrder::findOrFail($id);
if($shopping_order->member_id !== $user->id){
abort(404);
}
$data = [
'shopping_order' => $shopping_order,
'isAdmin' => false,
];
return view('user.shop.sales.order_detail', $data);
}
public function ordersDatatable(){
$user = User::find(\Auth::user()->id);
$query = ShoppingOrder::with('shopping_user')->select('shopping_orders.*')->where('member_id', $user->id);
return \DataTables::eloquent($query)
->addColumn('id', function (ShoppingOrder $ShoppingOrder) {
return '<a href="' . route('user_shop_order_detail', [$ShoppingOrder->id]) . '" class="btn icon-btn btn-sm btn-primary"><span class="fa fa-edit"></span></a>';
})
->addColumn('created_at', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->created_at->format("d.m.Y");
})
->addColumn('txaction', function (ShoppingOrder $ShoppingOrder) {
return Payment::getShoppingOrderBadge($ShoppingOrder);
})
->addColumn('total_shipping', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->getFormattedTotalShipping();
})
->addColumn('orders', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->shopping_user ? $ShoppingOrder->shopping_user->orders : '';
})
->addColumn('user_shop_id', function (ShoppingOrder $ShoppingOrder) {
return $ShoppingOrder->user_shop ? '<a href="'.$ShoppingOrder->user_shop->getSubdomain(false).'" target="_blank">'.$ShoppingOrder->user_shop->getSubdomain(false).'</span>' : '';
})
->orderColumn('id', 'id $1')
->orderColumn('txaction', 'txaction $1')
->orderColumn('user_shop_id', 'user_shop_id $1')
->rawColumns(['id', 'txaction', 'user_shop_id'])
->make(true);
}
}

View file

@ -39,6 +39,15 @@ class UserDataController extends Controller
/*if(!$user->account){
$user->account = new UserAccount();
}*/
$data = Request::all();
if(isset($data['action']) && $data['action'] == "reverse_charge_validate"){
return $this->userRepo->reverse_charge_validate($data, $user, route('user_edit', [$user->id]));
}
if(isset($data['action']) && $data['action'] == "reverse_charge_delete"){
return $this->userRepo->reverse_charge_delete($data, $user, route('user_edit', [$user->id]));
}
$rules = array(
'salutation' => 'required',
'first_name'=>'required',
@ -50,9 +59,6 @@ class UserDataController extends Controller
'mobil' => 'required_without:phone',
'tax_number' => 'required_without:tax_identification_number',
'tax_identification_number' => 'required_without:tax_number',
'birthday_day' => 'required',
'birthday_month' => 'required',
'birthday_year' => 'required',
'country_id' => 'required|integer|min:1',
'email' => 'required|string|email|max:255|exists:users,email',
'email-confirm' => 'required|same:email',
@ -79,7 +85,7 @@ class UserDataController extends Controller
} else {
$this->userRepo->update(Request::all());
\Session()->flash('alert-save', true);
return redirect('/user/edit');
return redirect(route('user_edit', [$user->id]));
}
}

View file

@ -24,7 +24,7 @@ class UserLevelController extends Controller
{
$data = [
'values' => UserLevel::all(),
'values' => UserLevel::orderBy('pos')->get(),
'trans' => array_keys(config('localization.supportedLocales')),
];
return view('admin.level.index', $data);
@ -57,6 +57,7 @@ class UserLevelController extends Controller
$user_level = UserLevel::create([
'name' => $data['name'],
'pos' => $data['pos'],
'payment_year' => isset($data['payment_year']) ? true : false,
'content' => $data['content'],
'partner_provision' => isset($data['partner_provision']) ? true : false,
'active' => isset($data['active']) ? true : false,
@ -65,6 +66,7 @@ class UserLevelController extends Controller
$user_level = UserLevel::find($data['id']);
$user_level->name = $data['name'];
$user_level->pos = $data['pos'];
$user_level->payment_year =isset($data['payment_year']) ? true : false;
$user_level->content = $data['content'];
$user_level->partner_provision = isset($data['partner_provision']) ? true : false;
$user_level->active = isset($data['active']) ? true : false;

View file

@ -270,7 +270,7 @@ class UserShopController extends Controller
if(Request::get('shop_submit') == 'check'){
$rules = array(
'user_shop_name' => ' required|alpha_dash|profanity|unique:user_shops,name|min:4|max:20|full_word_check',
'user_shop_name' => ' required|alpha_dash|unique:user_shops,name|min:4|max:20|full_word_check',
);
Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
if(in_array($value, config('profanity.full_word_check'))){
@ -291,7 +291,7 @@ class UserShopController extends Controller
if(Request::get('shop_submit') == 'action') {
$rules = array(
'user_shop_name' => ' required|alpha_dash|profanity|unique:user_shops,name|min:4|max:20|full_word_check',
'user_shop_name' => ' required|alpha_dash|unique:user_shops,name|min:4|max:20|full_word_check',
);
Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
if(in_array($value, config('profanity.full_word_check'))){
@ -343,8 +343,10 @@ class UserShopController extends Controller
public function userShopRegisterSubDomain($slug){
return ['success' => false, 'error' => 'no KAS'];
/*
$kas = new KasController();
$domain = 'mivita.care';
$domain = 'HIER DIE DOMAIN';
//check if exisist
@ -360,7 +362,7 @@ class UserShopController extends Controller
$pra = array(
'subdomain_name' => $slug,
'domain_name' => $domain,
'subdomain_path' => '/mein.mivita.care/public/',
'subdomain_path' => '/hier der Ordner /public/',
'php_version' => '7.3',
//'ssl_proxy' => 'Y',
//'redirect_status' => 0
@ -370,6 +372,7 @@ class UserShopController extends Controller
return ['success' => true];
}
return ['success' => false, 'error' => $add_subdomain];
*/
}
/**
@ -378,7 +381,7 @@ class UserShopController extends Controller
public function checkUserShopName(){
$rules = array(
'user_shop_name' => ' required|alpha_dash|profanity|unique:user_shops,name|min:4|max:20|full_word_check',
'user_shop_name' => ' required|alpha_dash|unique:user_shops,name|min:4|max:20|full_word_check',
);
Validator::extend('full_word_check', function ($attribute, $value, $parameters, $validator) {
if(in_array($value, config('profanity.full_word_check'))){

View file

@ -3,14 +3,15 @@
namespace App\Http\Controllers;
use App\Mail\MailActivateUser;
use App\User;
use Auth;
use Validator;
use Request;
use Carbon\Carbon;
use Illuminate\Database\Connection;
use App\Mail\MailActivateUser;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
use Request;
use Validator;
class UserUpdateEmailController extends Controller
{
@ -146,13 +147,13 @@ class UserUpdateEmailController extends Controller
public function sendActivationMail($user, array $data)
{
$token = $this->createActivation($user, $data);
Mail::to($data['email'])->send(new MailActivateUser($token, $user));
Mail::to($data['email'])->bcc(config('app.info_mail'))->send(new MailActivateUser($token, $user));
}
protected function getToken()
{
return hash_hmac('sha256', str_random(40), config('app.key'));
return hash_hmac('sha256', Str::random(40), config('app.key'));
}
public function createActivation($user, array $data)

View file

@ -2,15 +2,23 @@
namespace App\Http\Controllers\Web;
use Yard;
use Request;
use Response;
use Validator;
use App\Services\Util;
use App\Models\Product;
use App\Models\Category;
use App\Services\Payment;
use App\Models\UserHistory;
use App\Models\PaymentMethod;
use App\Models\PromotionUser;
use App\Models\ShoppingOrder;
use App\Models\ShoppingPayment;
use App\Services\UserCart;
use App\Models\PaymentTransaction;
use App\Http\Controllers\Controller;
use App\Repositories\CheckoutRepository;
class PromotionController extends Controller
{
@ -23,32 +31,57 @@ class PromotionController extends Controller
public function serve($path = null)
{
if(!isset($path)){
abort(402);
$path = 'grueneseele';
//abort(402);
}
if($path === 'impressum'){
return view('web.legal.impressum');
}
if($path === 'datenschutzerklaerung'){
return view('web.legal.datenschutzerklaerung');
}
if($path === 'widerrufsbelehrung'){
return view('web.legal.widerrufsbelehrung');
}
if($path === 'versandarten'){
return view('web.legal.versandarten');
}
//search for promo
$PromotionUser = PromotionUser::where('url', trim($path))->whereNull('user_deleted_at')->first();
if(!$PromotionUser){
abort(402);
}
if($PromotionUser->checkOutOfStock()){
if(!$PromotionUser->promotion_admin->isActive() || $PromotionUser->checkOutOfStock()){
$data = [
'promotion_user' => $PromotionUser,
];
return view('web.promotion.outofstock', $data);
}
UserCart::initYard('prom', null, $PromotionUser);
$first_category_id = false;
if(Request::get('catid')){
$first_category_id = Request::get('catid');
}
//$first_category = Category::where('active', true)->whereJsonContains('show_on', ['3'])->orderBy('pos', 'DESC')->first();
//$first_category_id = isset($first_category->id) ? $first_category->id : false;
$shop_products = $this->getShowProducts($first_category_id);
$data = [
'promotion_user' => $PromotionUser,
'shop_products' => Product::where('active', true)->whereJsonContains('show_on', ['1', '2', '3'])->orderBy('pos', 'ASC')->get(),
'shop_products' => $shop_products,
'user_payment_methods' => PaymentMethod::getDefaultAsArray()->toArray(),
'first_category_id' => $first_category_id,
'categories_by_show_on' => '3'
];
return view('web.promotion.index', $data);
}
public function goto($load, $id){
public function goto($load, $id, $transactionId=false, $reference=false, $identifier=false){
$PromotionUser = PromotionUser::findOrFail($id);
$data = [
'promotion_user' => $PromotionUser,
];
@ -56,15 +89,29 @@ class PromotionController extends Controller
if($load === 'thanksreminder'){
return view('web.promotion.thanksreminder', $data);
}
if($load === 'thanksorder'){
return view('web.promotion.thanksorder', $data);
}
if($load === 'notactive'){
return view('web.promotion.notactive', $data);
}
if($load === 'thanksorder'){
$payt = PaymentTransaction::findOrFail($transactionId);
if($payt->shopping_payment->reference != $reference){
abort(404);
}
Yard::instance('shopping')->destroy();
$checkRepo = new CheckoutRepository();
$checkRepo->destroy();
if(($payt->status === 'fnc' || $payt->status === 'vor' || $payt->status === 'pp' || $payt->status === 'non') && $payt->txaction === 'prev'){
$this->directPaymentStatus($payt, $identifier);
}
$data = [
'promotion_user' => $PromotionUser,
'order_reference' => $payt->shopping_payment->reference,
'pay_trans' => $payt,
];
return view('web.promotion.thanksorder', $data);
}
}
public function store($id){
$PromotionUser = PromotionUser::findOrFail($id);
@ -75,25 +122,171 @@ class PromotionController extends Controller
}
if($data['action'] === 'submit-reminder-service'){
return redirect(route('web_promotion_goto', ['thanksreminder', $PromotionUser->id]));
}
if($data['action'] === 'submit-promotion-order'){
return redirect(route('web_promotion_goto', ['thanksorder', $PromotionUser->id]));
}
$rules = array(
'billing_firstname'=>'required',
'billing_lastname'=>'required',
'billing_address'=>'required',
'billing_zipcode'=>'required',
'billing_city' => 'required',
'billing_state' => 'required',
'billing_email'=>'required|email',
);
dd($PromotionUser);
if(Request::get('same_as_billing')){
$rules = array_merge($rules, [
'shipping_firstname'=>'required',
'shipping_lastname'=>'required',
'shipping_address'=>'required',
'shipping_zipcode'=>'required',
'shipping_city' => 'required',
'shipping_salutation' => 'required'
]);
}
$validator = Validator::make(Request::all(), $rules);
if ($validator->fails()) {
return back()->withErrors($validator)->withInput(Request::all());
}
$identifier = Util::getToken();
$data['is_from'] = 'shopping';
$data['is_for'] = 'pr';
unset($data['_token']);
Yard::instance('shopping')->putYardExtra('shopping_data', $data);
UserHistory::create(['user_id' => $PromotionUser->user_id, 'action'=>'web_promotion_payment', 'status'=>1, 'product_id'=>null, 'identifier'=>$identifier]);
$checkRepo = new CheckoutRepository();
$checkRepo->setPromotion(7, $PromotionUser);
$checkRepo->init($identifier, $data);
return $checkRepo->makePayment();
}
}
private function directPaymentStatus(PaymentTransaction $payt, $identifier){
if(isset($payt->transmitted_data['param'])){
$shopping_order = ShoppingOrder::find($payt->transmitted_data['param']);
$shopping_payment = ShoppingPayment::where('reference', $payt->transmitted_data['reference'])->first();
$shopping_order->txaction = 'open';
$shopping_order->save();
$payt->txaction = "open";
//is Promotion Handel it
if($shopping_order->promotion_user_id > 0){
Payment::handelPromotionProduct($shopping_order);
}
if($shopping_payment){
//Payment::handelUserPayCredits($shopping_order, 'deduction');
if($payt->status === 'vor'){
$shopping_payment->txaction = 'open';
$shopping_order->txaction = 'open';
$payt->txaction = "open";
$shopping_order->save();
}
if($payt->status === 'pp'){
$send_link = Payment::paymentStatusPaidAction($shopping_order, true);
$shopping_payment->txaction = 'paid';
$shopping_order->txaction = 'paid';
$payt->txaction = "paid";
$shopping_order->save();
}
if($payt->status === 'fnc'){
$send_link = Payment::paymentStatusPaidAction($shopping_order, true);
$shopping_payment->txaction = 'paid';
$shopping_order->txaction = 'paid';
$payt->txaction = "paid";
$shopping_order->save();
}
if($payt->status === 'non'){
$send_link = Payment::paymentStatusPaidAction($shopping_order, true);
$shopping_payment->txaction = 'paid';
$shopping_order->txaction = 'paid';
$payt->txaction = "paid";
$shopping_order->save();
\App\Services\Shop::newUserOrder($shopping_order->shopping_user->number);
}
$shopping_payment->save();
}
$payt->save();
$data = [
'mode' => $payt->transmitted_data['mode'],
'txaction' => $payt->txaction,
'send_link' => false,
];
Payment::paymentStatusSendMail($shopping_order, $shopping_payment, $data);
}
}
public function load(){
$data = Request::all();
$ret = "";
$status = false;
if(Request::ajax()){
if($data['action'] === 'web-show-product'){
$product = Product::find($data['id']); //current user form order
$ret = view("web.promotion.show_product", compact('product', 'data'))->render();
}
if(isset($data['perform'])){
if($data['action'] === 'switch-show_products'){
$category_id = isset($data['show_products_option']) ? $data['show_products_option'] : false;
$shop_products = $this->getShowProducts($category_id);
$shop_products_view = view("web.promotion._shop_products_inner", compact('shop_products'))->render();
return response()->json(['response' => $data, 'shop_products_view'=>$shop_products_view, 'status'=>$status]);
}
if($data['action'] === 'switch-free-product'){
\App\Services\UserCart::updateFeeProduct($data);
}
if($data['action'] === 'add-shop-product'){
$data['qty'] = \App\Services\UserCart::updateProduct($data, true);
}
if($data['action'] === 'update-shop-product'){
$data['qty'] = \App\Services\UserCart::updateProduct($data);
}
if($data['action'] === 'remove-shop-product'){
\App\Services\UserCart::updateProduct($data);
$data['qty'] = 0;
}
if($data['action'] === 'clear-cart'){
\App\Services\UserCart::clearCart($data);
}
if($data['action'] === 'switch-shipping'){
\App\Services\UserCart::switchShipping($data);
}
if($data['action'] === 'change-state-shipping'){
\App\Services\UserCart::changeStateShipping($data, 'prom');
}
$cart = view("web.promotion._promotion_cart", compact('data'))->render();
if(Yard::instance('shopping')->isQuickShipping()){
$invoice = view("web.components._invoice_details_quick")->render();
}else{
$invoice = view("web.components._invoice_details")->render();
}
$checkout = view("web.components._checkout")->render();
$data['shipping_price_formated'] = UserCart::getCurrentShippingPrice(2); //shipping_for === 2 promotion , 3 shop
return response()->json(['response' => $data, 'cart'=>$cart, 'invoice'=>$invoice, 'checkout'=>$checkout, 'status'=>$status, 'basketqty'=>Yard::instance('shopping')->count()]);
}
return response()->json(['response' => $data, 'html'=>$ret, 'status'=>$status]);
}
}
private function getShowProducts($category_id = false){
$shop_products = [];
if($category_id){
$shop_products = Product::where('active', true)->whereJsonContains('show_on', ['3'])
->whereHas('categories', function ($query) use ($category_id) {
$query->where('category_id', $category_id); //->whereJsonContains('show_on', ['3']);
})->orderBy('pos', 'ASC')->get();
}else{
$shop_products = Product::where('active', true)->whereJsonContains('show_on', ['3'])
->orderBy('pos', 'ASC')->get();
}
return $shop_products;
}
}

View file

@ -3,19 +3,21 @@
namespace App\Http\Controllers\Web;
use App\Http\Controllers\Controller;
use App\Mail\MailContact;
use App\Mail\MailVerifyAccount;
use App\Models\UserHistory;
use App\Repositories\UserRepository;
use App\Services\SysLog;
use App\Services\UserService;
use App\User;
use GuzzleHttp\Client;
use Request;
use Illuminate\Support\Facades\Mail;
use App\Services\Util;
use App\User;
use Validator;
use App\Services\Util;
use GuzzleHttp\Client;
use App\Services\SysLog;
use App\Mail\MailContact;
use App\Models\UserHistory;
use App\Models\UserRegister;
use App\Services\UserService;
use App\Mail\MailVerifyAccount;
use App\Http\Controllers\Controller;
use App\Repositories\UserRepository;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Mail;
class RegisterController extends Controller
@ -34,33 +36,105 @@ class RegisterController extends Controller
$this->userRepo = $userRepo;
}
public function member($member_id = false)
public function showConsentPage()
{
$data = [
'from_member_id' => session('from_member_id')
];
return view('auth.recaptcha-consent', $data);
}
public function acceptConsent()
{
if (!Request::has('recaptcha_consent')) {
return back()->withErrors(['error' => 'Bitte stimmen Sie der Verwendung von reCAPTCHA zu']);
}
session(['recaptcha_consent' => true]);
return redirect()->route('register.form');
}
public function showRegistrationForm()
{
if (!session('recaptcha_consent')) {
return redirect()->route('register.consent');
}
$data = [
'from_member_id' => session('from_member_id')
];
return view('auth.register', $data);
}
public function member($from_member_id = false)
{
$this->userRepo->clearUserRegister();
if(!$from_member_id){
return redirect()->route('register.consent');
}
//ist ein gültiger Member ID und ist aktiv?
$user_id = (int) str_replace('gs', '', $from_member_id) - config('main.add_number_id');
$user = User::find($user_id);
if(!$user || !$user->isActive() || !$user->isActiveAccount()){
return redirect()->route('register.consent');
}
session(['from_member_id' => $from_member_id]);
return redirect()->route('register.consent');
/*
//hat einen Member ID?
if(!$member_id){
return redirect('/registrierung');
}
//ist ein gültiger Member ID und ist aktiv?
$user_id = (int) str_replace('gs', '', $member_id) - config('main.add_number_id');
$user = User::find($user_id);
if(!$user || !$user->isActive() || !$user->isActiveAccount()){
return redirect('/registrierung');
}
if (!session('recaptcha_consent')) {
$data = [
'from_member_id' => Request::get('from_member_id')
];
return view('auth.recaptcha-consent', $data);
//return redirect()->route('register.consent')->with(['from_member_id' => $member_id]);
}
$data = [
'from_member_id' => $member_id
];
return view('auth.register', $data);
*/
}
public function register(){
public function register(){
$this->userRepo->clearUserRegister();
// Überprüfe zuerst die reCAPTCHA-Einwilligung
/* if (!Request::has('recaptcha_consent')) {
return back()->withErrors(['recaptcha_consent' => 'Bitte stimmen Sie der Verwendung von reCAPTCHA zu'])->withInput(Request::all());
}*/
// Überprüfe reCAPTCHA
$recaptchaResponse = Request::input('g-recaptcha-response');
if (!$this->verifyRecaptcha($recaptchaResponse)) {
return back()->withErrors(['g-recaptcha-response' => 'Bitte bestätigen Sie, dass Sie kein Roboter sind'])->withInput(Request::all());
}
$rules = array(
'salutation' => 'required',
'first_name'=>'required',
'last_name'=>'required',
'first_name'=>'required|string|min:2',
'last_name'=>'required|string|min:2',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
'password_confirmation' => 'required|string|min:6',
'accepted_data_protection' => 'required',
'g-recaptcha-response' => 'required',
);
$validator = Validator::make(Request::all(), $rules);
@ -68,37 +142,54 @@ class RegisterController extends Controller
return back()->withErrors($validator)->withInput(Request::all());
}
//search in UserRegister
$data = Request::all();
$user = $this->userRepo->create($data);
$confirmation_code = UserService::createConfirmationCode();
$user->lang = !empty(\App::getLocale()) ? \App::getLocale() : "de";
$user->confirmation_code = $confirmation_code;
$user->confirmation_code_to = date('Y-m-d H:i:s', strtotime('+1 week'));
$user->confirmation_code_remider = 0;
if(isset($data['from_member_id'])){
$user->m_sponsor = (int) str_replace('gs', '', $data['from_member_id']) - config('main.add_number_id');
$UserRegister = UserRegister::where('identifier', $data['email'])->first();
if($UserRegister){
$exists = [
'register_email' => $data['email']
];
return view('auth.existing', $exists);
}
$user->save();
$user = User::find($user->id);
$userObj = $this->userRepo->createUserRegister($data);
$from_member_id = session('from_member_id');
$user_id = isset($from_member_id) ? (int) str_replace('gs', '', $from_member_id) - config('main.add_number_id') : config('app.main_user_id'); // Krummel
try {
Mail::to($user->email)->send(new MailVerifyAccount($confirmation_code, $user));
Mail::to($userObj->email)->bcc(config('app.info_mail'))->send(new MailVerifyAccount($userObj->confirmation_code, $userObj));
}
catch(\Exception $e){
SysLog::action('register-user', 'auth_register', 5)
->setUserId($user->id)
->setModel($user->id, User::class)
->setUserId($user_id)
->setModel(null, UserRegister::class)
->setMessage('Error send register E-Mail: '.$e->getMessage())
->save();
}
UserHistory::create(['user_id' => $user->id, 'action'=>'register', 'status'=>0]);
UserHistory::create(['user_id' => $user_id, 'action'=>'register', 'status'=>0]);
return redirect('/user_register/finish');
}
// Neue Methode zur Überprüfung des reCAPTCHA
private function verifyRecaptcha($recaptchaResponse)
{
if (empty($recaptchaResponse)) {
return false;
}
$client = new Client();
$response = $client->post('https://www.google.com/recaptcha/api/siteverify', [
'form_params' => [
'secret' => config('services.recaptcha.secret_key'),
'response' => $recaptchaResponse
]
]);
$body = json_decode((string)$response->getBody());
return $body->success;
}
public function finish()
{
$data = [
@ -106,4 +197,40 @@ class RegisterController extends Controller
];
return view('auth.finish', $data);
}
public function verify($confirmation_code){
if( ! $confirmation_code)
{
return redirect('/status/error');
}
$UserRegister = UserRegister::where ('instance', $confirmation_code)->first();
if ( ! $UserRegister)
{
return redirect('/status/not/found');
}
$user = $this->userRepo->create($UserRegister);
//Login!
Auth::login($user);
return redirect('/home');
}
public function registerAgain(){
$data = Request::all();
if(!isset($data['register_email'])){
abort(403, "No E-Mail");
}
$UserRegister = UserRegister::where('identifier', $data['register_email'])->first();
if(!$UserRegister){
abort(403, "No E-Mail Register");
}
Mail::to($UserRegister->identifier)->bcc(config('app.info_mail'))->send(new MailVerifyAccount($UserRegister->instance, $UserRegister->content));
return redirect('/user_register/finish');
}
}

View file

@ -0,0 +1,294 @@
<?php
namespace App\Http\Controllers\Web;
use Yard;
use Request;
use Response;
use Validator;
use App\Services\Util;
use App\Models\Product;
use App\Models\UserShop;
use App\Services\Payment;
use App\Models\UserHistory;
use App\Models\PaymentMethod;
use App\Models\ShoppingOrder;
use App\Models\ShoppingPayment;
use App\Services\UserCart;
use App\Models\PaymentTransaction;
use App\Http\Controllers\Controller;
use App\Repositories\CheckoutRepository;
class ShopController extends Controller
{
public function __construct()
{
}
public function serve($path = null)
{
if(!isset($path)){
$path = 'grueneseele';
//abort(402);
}
if($path === 'impressum'){
return view('web.legal.impressum');
}
if($path === 'datenschutzerklaerung'){
return view('web.legal.datenschutzerklaerung');
}
if($path === 'widerrufsbelehrung'){
return view('web.legal.widerrufsbelehrung');
}
if($path === 'versandarten'){
return view('web.legal.versandarten');
}
//search for promo
$userShop = UserShop::where('url', trim($path))->first();
if(!$userShop){
//redirect !!!!
abort(402);
}
if(!$userShop->isActive()){
$data = [
'user_shop' => $userShop,
];
//redirect !!!!
return view('web.shop.outofstock', $data);
}
UserCart::initYard('shop', $userShop, null);
$first_category_id = false;
if(Request::get('catid')){
$first_category_id = Request::get('catid');
}
$userMargin = \App\Services\Shop::calculateUserShopMargins($userShop, null);
//$first_category = Category::where('active', true)->whereJsonContains('show_on', ['8'])->orderBy('pos', 'DESC')->first();
// $first_category_id = isset($first_category->id) ? $first_category->id : false;
$shop_products = $this->getShowProducts($first_category_id);
$data = [
'user_shop' => $userShop,
'shop_products' => $shop_products,
'user_payment_methods' => PaymentMethod::getDefaultAsArray()->toArray(),
'first_category_id' => $first_category_id,
'categories_by_show_on' => '8',
'userMargin' => $userMargin
];
return view('web.shop.index', $data);
}
public function goto($load, $user_shop_id, $transactionId=false, $reference=false, $identifier=false){
$userShop = UserShop::findOrFail($user_shop_id);
$data = [
'user_shop' => $userShop,
];
if($load === 'thanksreminder'){
return view('web.shop.thanksreminder', $data);
}
if($load === 'notactive'){
return view('web.shop.notactive', $data);
}
if($load === 'thanksorder'){
$payt = PaymentTransaction::findOrFail($transactionId);
if($payt->shopping_payment->reference != $reference){
abort(404);
}
Yard::instance('shopping')->destroy();
$checkRepo = new CheckoutRepository();
$checkRepo->destroy();
if(($payt->status === 'fnc' || $payt->status === 'vor' || $payt->status === 'pp' || $payt->status === 'non') && $payt->txaction === 'prev'){
$this->directPaymentStatus($payt, $identifier);
}
$data = [
'user_shop' => $userShop,
'order_reference' => $payt->shopping_payment->reference,
'pay_trans' => $payt,
];
return view('web.shop.thanksorder', $data);
}
}
public function store($user_shop_id){
$userShop = UserShop::findOrFail($user_shop_id);
$data = Request::all();
if(!isset($data['action'])){
abort(402);
}
if($data['action'] === 'submit-reminder-service'){
return redirect(route('web_shop_goto', ['thanksreminder', $userShop->id]));
}
if($data['action'] === 'submit-order'){
$rules = array(
'billing_firstname'=>'required',
'billing_lastname'=>'required',
'billing_address'=>'required',
'billing_zipcode'=>'required',
'billing_city' => 'required',
'billing_state' => 'required',
'billing_email'=>'required|email',
);
if(Request::get('same_as_billing')){
$rules = array_merge($rules, [
'shipping_firstname'=>'required',
'shipping_lastname'=>'required',
'shipping_address'=>'required',
'shipping_zipcode'=>'required',
'shipping_city' => 'required',
'shipping_salutation' => 'required'
]);
}
$validator = Validator::make(Request::all(), $rules);
if ($validator->fails()) {
return back()->withErrors($validator)->withInput(Request::all());
}
$identifier = Util::getToken();
$data['is_from'] = 'shopping';
$data['is_for'] = 'us'; //usershopping
unset($data['_token']);
Yard::instance('shopping')->putYardExtra('shopping_data', $data);
UserHistory::create(['user_id' => $userShop->user_id, 'action'=>'web_shop_payment', 'status'=>1, 'product_id'=>null, 'identifier'=>$identifier]);
$checkRepo = new CheckoutRepository();
$checkRepo->setUserShop(8, $userShop);
$checkRepo->init($identifier, $data);
return $checkRepo->makePayment();
}
}
private function directPaymentStatus(PaymentTransaction $payt, $identifier){
if(isset($payt->transmitted_data['param'])){
$shopping_order = ShoppingOrder::find($payt->transmitted_data['param']);
$shopping_payment = ShoppingPayment::where('reference', $payt->transmitted_data['reference'])->first();
$shopping_order->txaction = 'open';
$shopping_order->save();
$payt->txaction = "open";
//is Promotion Handel it
if($shopping_order->promotion_user_id > 0){
Payment::handelPromotionProduct($shopping_order);
}
if($shopping_payment){
//Payment::handelUserPayCredits($shopping_order, 'deduction');
if($payt->status === 'vor'){
$shopping_payment->txaction = 'open';
$shopping_order->txaction = 'open';
$payt->txaction = "open";
$shopping_order->save();
}
if($payt->status === 'pp'){
$send_link = Payment::paymentStatusPaidAction($shopping_order, true);
$shopping_payment->txaction = 'paid';
$shopping_order->txaction = 'paid';
$payt->txaction = "paid";
$shopping_order->save();
}
if($payt->status === 'fnc'){
$send_link = Payment::paymentStatusPaidAction($shopping_order, true);
$shopping_payment->txaction = 'paid';
$shopping_order->txaction = 'paid';
$payt->txaction = "paid";
$shopping_order->save();
}
if($payt->status === 'non'){
$send_link = Payment::paymentStatusPaidAction($shopping_order, true);
$shopping_payment->txaction = 'paid';
$shopping_order->txaction = 'paid';
$payt->txaction = "paid";
$shopping_order->save();
\App\Services\Shop::newUserOrder($shopping_order->shopping_user->number);
}
$shopping_payment->save();
}
$payt->save();
$data = [
'mode' => $payt->transmitted_data['mode'],
'txaction' => $payt->txaction,
'send_link' => false,
];
Payment::paymentStatusSendMail($shopping_order, $shopping_payment, $data);
}
}
public function load(){
$data = Request::all();
$ret = "";
$status = false;
if(Request::ajax()){
if($data['action'] === 'web-show-product'){
$product = Product::find($data['id']); //current user form order
$ret = view("web.shop.show_product", compact('product', 'data'))->render();
}
if(isset($data['perform'])){
if($data['action'] === 'switch-show_products'){
$category_id = isset($data['show_products_option']) ? $data['show_products_option'] : false;
$shop_products = $this->getShowProducts($category_id);
$shop_products_view = view("web.shop._shop_products_inner", compact('shop_products'))->render();
return response()->json(['response' => $data, 'shop_products_view'=>$shop_products_view, 'status'=>$status]);
}
if($data['action'] === 'add-shop-product'){
$data['qty'] = \App\Services\UserCart::updateProduct($data, true);
}
if($data['action'] === 'minus-shop-product'){
$data['qty'] = \App\Services\UserCart::updateProduct($data, false, true);
}
if($data['action'] === 'update-shop-product'){
$data['qty'] = \App\Services\UserCart::updateProduct($data);
}
if($data['action'] === 'remove-shop-product'){
\App\Services\UserCart::updateProduct($data);
$data['qty'] = 0;
}
if($data['action'] === 'clear-cart'){
\App\Services\UserCart::clearCart($data);
}
if($data['action'] === 'switch-shipping'){
\App\Services\UserCart::switchShipping($data);
}
if($data['action'] === 'change-state-shipping'){
\App\Services\UserCart::changeStateShipping($data, 'shop');
}
$cart = view("web.shop._shop_cart", compact('data'))->render();
if(Yard::instance('shopping')->isQuickShipping()){
$invoice = view("web.components._invoice_details_quick")->render();
}else{
$invoice = view("web.components._invoice_details")->render();
}
$checkout = view("web.components._checkout")->render();
$data['shipping_price_formated'] = UserCart::getCurrentShippingPrice(3); //shipping_for === 2 promotion , 3 shop
return response()->json(['response' => $data, 'cart'=>$cart, 'invoice'=>$invoice, 'checkout'=>$checkout, 'status'=>$status, 'basketqty'=>Yard::instance('shopping')->count()]);
}
return response()->json(['response' => $data, 'html'=>$ret, 'status'=>$status]);
}
}
private function getShowProducts($category_id = false){
$shop_products = [];
if($category_id){
$shop_products = Product::where('active', true)->whereJsonContains('show_on', ['8'])
->whereHas('categories', function ($query) use ($category_id) {
$query->where('category_id', $category_id); //->whereJsonContains('show_on', ['3']);
})->orderBy('pos', 'ASC')->get();
}else{
$shop_products = Product::where('active', true)->whereJsonContains('show_on', ['8'])
->orderBy('pos', 'ASC')->get();
}
return $shop_products;
}
}

View file

@ -2,22 +2,23 @@
namespace App\Http\Controllers;
use App\Mail\MailReleaseAccount;
use App\Models\File;
use App\Models\Product;
use App\Models\ShoppingInstance;
use App\Models\UserAccount;
use App\Models\UserHistory;
use App\Models\UserLevel;
use App\Repositories\FileRepository;
use App\Services\Util;
use App\User;
use Auth;
use Hash;
use Illuminate\Support\Facades\Mail;
use Request;
use Validator;
use Yard;
use Request;
use App\User;
use Validator;
use App\Models\File;
use App\Services\Util;
use App\Models\Product;
use App\Models\UserLevel;
use App\Models\UserAccount;
use App\Models\UserHistory;
use App\Mail\MailReleaseAccount;
use App\Models\ShoppingInstance;
use App\Repositories\FileRepository;
use App\Repositories\UserRepository;
use Illuminate\Support\Facades\Mail;
class WizardController extends Controller
{
@ -95,7 +96,7 @@ class WizardController extends Controller
$data = [
'user' => Auth::user(),
'step' => $step,
'user_levels' => UserLevel::where('active', true)->get(),
'user_levels' => UserLevel::where('active', true)->orderBy('pos', 'ASC')->get(),
//'products' => Product::where('active', true)->whereJsonContains('show_on', ['4', '5'])->orderBy('pos', 'ASC')->get(),
//'products_on_board' => Product::where('active', true)->whereJsonContains('show_on', '6')->orderBy('pos', 'ASC')->get(),
@ -150,6 +151,12 @@ class WizardController extends Controller
$user->account = new UserAccount();
}
$data = Request::all();
if($step == 7 && Request::get('user_country_id')){
$user->account->country_id = Request::get('user_country_id');
$user->account->save();
return redirect(route('wizard_register', [1]));
}
if ($step == 0) {
$rules = array(
'accepted_data_protection' => 'required',
@ -161,7 +168,7 @@ class WizardController extends Controller
$data = [
'user' => Auth::user(),
'step' => $step,
'user_levels' => UserLevel::where('active', true)->get(),
'user_levels' => UserLevel::where('active', true)->orderBy('pos', 'ASC')->get(),
//'products' => Product::where('active', true)->whereJsonContains('show_on', ['4', '5'])->orderBy('pos', 'ASC')->get(),
//'products_on_board' => Product::where('active', true)->whereJsonContains('show_on', '6')->orderBy('pos', 'ASC')->get(),,
];
@ -185,7 +192,23 @@ class WizardController extends Controller
$user->save();
return redirect(route('wizard_register'));
}
if ($step == 1) {
$data = Request::all();
if(isset($data['action']) && $data['action'] == "reverse_charge_validate"){
$user->wizard = 1;
$user->save();
$userRepo = new UserRepository($user);
return $userRepo->reverse_charge_validate($data, $user, route('wizard_register', [1]));
}
if(isset($data['action']) && $data['action'] == "reverse_charge_delete"){
$user->wizard = 1;
$user->save();
$userRepo = new UserRepository($user);
return $userRepo->reverse_charge_delete($data, $user, route('wizard_register', [1]));
}
$rules = array(
'salutation' => 'required',
'first_name' => 'required',
@ -198,9 +221,6 @@ class WizardController extends Controller
'tax_number' => 'required_without:tax_identification_number',
'tax_identification_number' => 'required_without:tax_number',
'country_id' => 'required|integer|min:1',
'birthday_day' => 'required',
'birthday_month' => 'required',
'birthday_year' => 'required'
);
if (!Request::get('same_as_billing')) {
@ -220,19 +240,26 @@ class WizardController extends Controller
$user->save();
return redirect(route('wizard_register', [1]))->withErrors($validator)->withInput(Request::all());
}
$data = Request::all();
$data['same_as_billing'] = Request::get('same_as_billing') == NULL ? 0 : 1;
$data['birthday_day'] = isset($data['birthday_day']) ? $data['birthday_day'] : 1;
$data['birthday_month'] = isset($data['birthday_month']) ? $data['birthday_month'] : 1;
$data['birthday_year'] = isset($data['birthday_year']) ? $data['birthday_year'] : 1970;
$data['birthday_year'] = isset($data['birthday_year']) ? $data['birthday_year'] : 1900;
$data['birthday'] = $data['birthday_day'].".".$data['birthday_month'].".".$data['birthday_year'];
$data['birthday'] = $data['birthday'] == "1.1.1900" ? null : $data['birthday'];
$user->account->fill($data)->save();
$user->wizard = 2;
$user->save();
return redirect(route('wizard_register'));
}
if ($step == 2) {
/* if ($step == 2) {
//kein Ausweis hochladen - deaktiviert
dd("deaktiviert");
$user->wizard = 3;
$user->save();
return redirect(route('wizard_register'));
/*
if(Request::get('submit') === 'do'){
if(File::whereUserId($user->id)->whereIdentifier('id_card')->count() == 0){
$validator = Validator::make(Request::all(), []);
@ -251,8 +278,10 @@ class WizardController extends Controller
$this->fileRepo->_set('identifier', 'id_card');
return $this->fileRepo->uploadFile(Request::all());
}
*/
if ($step == 3) {
if ($step == 2) {
$data = Request::all();
if(Request::get('submit') === 'do'){
$data = Request::all();
@ -260,7 +289,7 @@ class WizardController extends Controller
if(File::whereUserId($user->id)->whereIdentifier('business_license')->count() == 0){
$validator = Validator::make(Request::all(), []);
$validator->errors()->add('field', __('Kein Gewerbeschein hinterlegt, bitte erst hochladen.'));
$user->wizard = 3;
$user->wizard = 2;
$user->save();
return redirect(route('wizard_register'))->withErrors($validator)->withInput(Request::all());
}
@ -272,7 +301,7 @@ class WizardController extends Controller
if(!$data['non_business_license_reason'] || $data['non_business_license_reason'] == ""){
$validator = Validator::make(Request::all(), []);
$validator->errors()->add('field', __('Bitte gib eine Begründung ein, warum Du keinen Gewerbeschein benötigst.'));
$user->wizard = 3;
$user->wizard = 2;
$user->save();
return redirect(route('wizard_register'))->withErrors($validator)->withInput(Request::all());
}else{
@ -281,7 +310,7 @@ class WizardController extends Controller
}
$user->account->setNotice('business_license', $data['business_license_choose']);
$user->wizard = 4;
$user->wizard = 3;
$user->save();
return redirect(route('wizard_register'));
@ -293,7 +322,7 @@ class WizardController extends Controller
return $this->fileRepo->uploadFile(Request::all());
}
if ($step == 4) {
if ($step == 3) {
$data = Request::all();
@ -397,6 +426,23 @@ class WizardController extends Controller
return redirect(route('wizard_create', [12]));
}
if($step == 12){
$data = Request::all();
if(isset($data['action']) && $data['action'] == "reverse_charge_validate"){
$user->wizard = 12;
$user->save();
$userRepo = new UserRepository($user);
return $userRepo->reverse_charge_validate($data, $user, route('wizard_create', [12]));
}
if(isset($data['action']) && $data['action'] == "reverse_charge_delete"){
$user->wizard = 12;
$user->save();
$userRepo = new UserRepository($user);
return $userRepo->reverse_charge_delete($data, $user, route('wizard_create', [12]));
}
$rules = array(
'salutation' => 'required',
'first_name' => 'required',
@ -409,9 +455,6 @@ class WizardController extends Controller
'tax_number' => 'required_without:tax_identification_number',
'tax_identification_number' => 'required_without:tax_number',
'country_id' => 'required|integer|min:1',
'birthday_day' => 'required',
'birthday_month' => 'required',
'birthday_year' => 'required'
);
if(!Request::get('same_as_billing')){
@ -464,6 +507,15 @@ class WizardController extends Controller
if($product->images->count()){
$image = $product->images->first()->slug;
}
/*need setGlobalTaxRate
$cartItem = Yard::instance('shopping')->add($product->id, $product->getLang('name'), 1, $product->getPriceWith(\App\Services\UserService::getTaxFree(), false, \App\Services\UserService::$user_country), false, false, ['image' => $image, 'slug' => $product->slug, 'weight' => $product->weight, 'points' => $product->points, 'no_commission' => $product->no_commission]);
if(\App\Services\UserService::getTaxFree()){
Yard::setTax($cartItem->rowId, 0);
}else{
Yard::setTax($cartItem->rowId, $product->getTaxWith(\App\Services\UserService::$user_country));
}
*/
//Keine steuer
Yard::instance('shopping')->add($product->id, $product->getLang('name'), 1, $product->price, $product->tax, ['image' => $image, 'slug' => $product->slug, 'weight' => $product->weight]);
Yard::instance('shopping')->setGlobalTaxRate(0);
@ -475,6 +527,18 @@ class WizardController extends Controller
if($product_on_board->images->count()){
$image = $product_on_board->images->first()->slug;
}
/*
need?
$cartItem = Yard::instance('shopping')->add($product_on_board->id, $product_on_board->getLang('name'), 1,
$product_on_board->getPriceWith(\App\Services\UserService::getTaxFree(), false, \App\Services\UserService::$user_country),
false, false, ['image' => $image, 'slug' => $product_on_board->slug, 'weight' => $product_on_board->weight, 'points' => $product_on_board->points, 'no_commission' => $product_on_board->no_commission]);
if(\App\Services\UserService::getTaxFree()){
Yard::setTax($cartItem->rowId, 0);
}else{
Yard::setTax($cartItem->rowId, $product->getTaxWith(\App\Services\UserService::$user_country));
}
*/
Yard::instance('shopping')->add($product_on_board->id, $product_on_board->getLang('name'), 1, $product_on_board->price, $product->tax, ['image' => $image, 'slug' => $product_on_board->slug, 'weight' => $product_on_board->weight]);
}
}
@ -522,10 +586,16 @@ class WizardController extends Controller
if($relation === 'upload'){
$user = User::findOrFail(Auth::user()->id);
$file = $user->files()->findOrFail($id);
$identifier = $file->identifier;
//remove file
\Storage::disk('user')->delete($file->dir.$file->filename);
$file->delete();
\Session()->flash('alert-success', "Datei gelöscht");
if($identifier === 'business_license'){
$user->wizard = 2;
$user->save();
return redirect(route('wizard_register', [2]));
}
}
return back();
}

View file

@ -15,7 +15,7 @@ class Kernel extends HttpKernel
*/
protected $middleware = [
\App\Http\Middleware\TrustProxies::class,
\Fruitcake\Cors\HandleCors::class,
\Illuminate\Http\Middleware\HandleCors::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
@ -54,6 +54,7 @@ class Kernel extends HttpKernel
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'copyreader' => \App\Http\Middleware\CopyReader::class,
'admin' => \App\Http\Middleware\Admin::class,
'superadmin' => \App\Http\Middleware\SuperAdmin::class,
'sysadmin' => \App\Http\Middleware\SysAdmin::class,

View file

@ -0,0 +1,26 @@
<?php
namespace App\Http\Middleware;
use Closure;
use Auth;
class CopyReader
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ( Auth::check() && Auth::user()->isCopyReader() )
{
return $next($request);
}
return redirect('/home');
}
}

View file

@ -2,15 +2,15 @@
namespace App\Http\Middleware;
use Illuminate\Http\Middleware\TrustProxies as Middleware;
use Illuminate\Http\Request;
use Fideloper\Proxy\TrustProxies as Middleware;
class TrustProxies extends Middleware
{
/**
* The trusted proxies for this application.
*
* @var array|string
* @var array|string|null
*/
protected $proxies;
@ -19,5 +19,10 @@ class TrustProxies extends Middleware
*
* @var int
*/
protected $headers = Request::HEADER_X_FORWARDED_ALL;
protected $headers =
Request::HEADER_X_FORWARDED_FOR |
Request::HEADER_X_FORWARDED_HOST |
Request::HEADER_X_FORWARDED_PORT |
Request::HEADER_X_FORWARDED_PROTO |
Request::HEADER_X_FORWARDED_AWS_ELB;
}

View file

@ -0,0 +1,50 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Validator;
class ReceiveStockEntryRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, mixed>>
*/
public function rules(): array
{
return [
'received_at' => ['required', 'date'],
'received_quantity' => ['required', 'numeric', 'min:0.000001'],
'batch_number' => ['nullable', 'string', 'max:100'],
'best_before' => ['nullable', 'date'],
'quality_id' => ['nullable', 'integer', 'exists:material_qualities,id'],
];
}
protected function prepareForValidation(): void
{
$this->merge([
'received_quantity' => reFormatNumber($this->input('received_quantity')),
]);
}
public function withValidator(Validator $validator): void
{
$validator->after(function (Validator $validator): void {
$stockEntry = $this->route('stockEntry') ?? $this->route('stock_entry');
if ($stockEntry && $stockEntry->entry_type === 'ingredient') {
if (empty($this->input('batch_number'))) {
$validator->errors()->add('batch_number', __('Bitte eine Chargennummer angeben.'));
}
if (empty($this->input('best_before'))) {
$validator->errors()->add('best_before', __('Bitte die Mindesthaltbarkeit angeben.'));
}
}
});
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
class StoreLocationRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, string>>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'active' => ['sometimes', 'boolean'],
];
}
protected function prepareForValidation(): void
{
$this->merge([
'active' => $this->boolean('active'),
]);
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
class StoreMaterialQualityRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, string>>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'pos' => ['nullable', 'integer', 'min:0', 'max:255'],
];
}
protected function prepareForValidation(): void
{
if ($this->has('pos') && $this->input('pos') === '') {
$this->merge(['pos' => 0]);
}
}
}

View file

@ -0,0 +1,47 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class StorePackagingItemRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, mixed>>
*/
public function rules(): array
{
return [
'packaging_material_id' => ['required', 'integer', 'exists:packaging_materials,id'],
'supplier_id' => ['nullable', 'integer', 'exists:suppliers,id'],
'name' => ['required', 'string', 'max:255'],
'category' => ['required', Rule::in(['packaging', 'shipping'])],
'weight_grams' => ['nullable', 'numeric', 'min:0'],
'min_stock_alert' => ['nullable', 'integer', 'min:0'],
'url' => ['nullable', 'url', 'max:500'],
'product_id' => ['nullable', 'integer', 'exists:products,id'],
'active' => ['sometimes', 'boolean'],
];
}
protected function prepareForValidation(): void
{
$this->merge([
'active' => $this->boolean('active'),
'category' => trim((string) $this->input('category')),
'weight_grams' => $this->filled('weight_grams') ? reFormatNumber($this->input('weight_grams')) : null,
]);
foreach (['supplier_id', 'product_id', 'min_stock_alert'] as $key) {
if ($this->input($key) === '' || $this->input($key) === null) {
$this->merge([$key => null]);
}
}
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
class StorePackagingMaterialRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, string>>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'pos' => ['nullable', 'integer', 'min:0', 'max:255'],
];
}
protected function prepareForValidation(): void
{
if ($this->has('pos') && $this->input('pos') === '') {
$this->merge(['pos' => 0]);
}
}
}

View file

@ -0,0 +1,54 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
class StoreProductionRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, mixed|string>>
*/
public function rules(): array
{
return [
'product_id' => ['required', 'integer', 'exists:products,id'],
'location_id' => ['required', 'integer', 'exists:locations,id'],
'produced_at' => ['required', 'date'],
'quantity' => ['required', 'integer', 'min:1'],
'notes' => ['nullable', 'string', 'max:2000'],
'ingredient_lines' => ['required', 'array', 'min:1'],
'ingredient_lines.*.ingredient_id' => ['required', 'integer', 'exists:ingredients,id'],
'ingredient_lines.*.stock_entry_id' => ['required', 'integer', 'exists:stock_entries,id'],
'ingredient_lines.*.quantity_used' => ['required', 'string'],
];
}
/**
* @return array<string, mixed>
*/
public function validatedPayload(): array
{
$data = $this->validated();
return [
'product_id' => (int) $data['product_id'],
'location_id' => (int) $data['location_id'],
'produced_at' => $data['produced_at'],
'quantity' => (int) $data['quantity'],
'notes' => $data['notes'] ?? null,
'ingredient_lines' => array_map(function (array $line): array {
return [
'ingredient_id' => (int) $line['ingredient_id'],
'stock_entry_id' => (int) $line['stock_entry_id'],
'quantity_used' => $line['quantity_used'],
];
}, $data['ingredient_lines']),
];
}
}

View file

@ -0,0 +1,96 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator;
class StoreStockEntryRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, mixed>>
*/
public function rules(): array
{
return [
'entry_type' => ['required', Rule::in(['ingredient', 'packaging', 'shipping'])],
'ingredient_id' => ['nullable', 'integer', 'exists:ingredients,id'],
'packaging_item_id' => ['nullable', 'integer', 'exists:packaging_items,id'],
'supplier_id' => ['required', 'integer', 'exists:suppliers,id'],
'location_id' => ['required', 'integer', 'exists:locations,id'],
'ordered_at' => ['required', 'date'],
'ordered_quantity' => ['required', 'numeric', 'min:0.000001'],
'quality_id' => ['nullable', 'integer', 'exists:material_qualities,id'],
'price_per_kg' => ['nullable', 'numeric', 'min:0'],
'price_total' => ['nullable', 'numeric', 'min:0'],
];
}
/**
* @return array<string, string>
*/
public function messages(): array
{
return [
'quality_id.required' => __('Bitte eine Rohstoffqualität wählen.'),
'price_per_kg.required' => __('Bitte den Netto-Preis pro kg angeben.'),
'price_total.required' => __('Bitte den Gesamtpreis netto angeben.'),
];
}
protected function prepareForValidation(): void
{
$this->merge([
'ordered_quantity' => reFormatNumber($this->input('ordered_quantity')),
'price_per_kg' => $this->filled('price_per_kg') ? reFormatNumber($this->input('price_per_kg')) : null,
'price_total' => $this->filled('price_total') ? reFormatNumber($this->input('price_total')) : null,
]);
}
public function withValidator(Validator $validator): void
{
$validator->after(function (Validator $validator): void {
$type = $this->input('entry_type');
if ($type === 'ingredient') {
if (empty($this->input('ingredient_id'))) {
$validator->errors()->add('ingredient_id', __('Bitte einen Inhaltsstoff wählen.'));
}
if (empty($this->input('quality_id'))) {
$validator->errors()->add('quality_id', __('Bitte eine Rohstoffqualität wählen.'));
}
if (! is_numeric($this->input('price_per_kg')) || (float) $this->input('price_per_kg') <= 0) {
$validator->errors()->add('price_per_kg', __('Bitte den Netto-Preis pro kg angeben.'));
}
} elseif (! empty($type)) {
if (empty($this->input('packaging_item_id'))) {
$validator->errors()->add('packaging_item_id', __('Bitte einen Verpackungsartikel wählen.'));
}
if (! is_numeric($this->input('price_total')) || (float) $this->input('price_total') <= 0) {
$validator->errors()->add('price_total', __('Bitte den Gesamtpreis netto angeben.'));
}
}
});
}
/**
* @return array<string, mixed>
*/
public function validatedPayload(): array
{
$data = $this->validated();
if (($data['entry_type'] ?? '') === 'ingredient') {
$data['packaging_item_id'] = null;
} else {
$data['ingredient_id'] = null;
$data['quality_id'] = null;
}
return $data;
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
class StoreSupplierCategoryRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, string>>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'pos' => ['nullable', 'integer', 'min:0', 'max:255'],
];
}
protected function prepareForValidation(): void
{
if ($this->has('pos') && $this->input('pos') === '') {
$this->merge(['pos' => 0]);
}
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
class StoreSupplierRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, mixed>>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'url' => ['nullable', 'string', 'max:2048'],
'contact_person' => ['nullable', 'string', 'max:255'],
'email' => ['nullable', 'email', 'max:255'],
'phone' => ['nullable', 'string', 'max:100'],
'country_id' => ['required', 'integer', 'exists:countries,id'],
'notes' => ['nullable', 'string'],
'active' => ['sometimes', 'boolean'],
'supplier_category_ids' => ['nullable', 'array'],
'supplier_category_ids.*' => ['integer', 'exists:supplier_categories,id'],
];
}
protected function prepareForValidation(): void
{
$this->merge([
'active' => $this->boolean('active'),
]);
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
class UpdateLocationRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, string>>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'active' => ['sometimes', 'boolean'],
];
}
protected function prepareForValidation(): void
{
$this->merge([
'active' => $this->boolean('active'),
]);
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
class UpdateMaterialQualityRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, string>>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'pos' => ['nullable', 'integer', 'min:0', 'max:255'],
];
}
protected function prepareForValidation(): void
{
if ($this->has('pos') && $this->input('pos') === '') {
$this->merge(['pos' => 0]);
}
}
}

View file

@ -0,0 +1,47 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class UpdatePackagingItemRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, mixed>>
*/
public function rules(): array
{
return [
'packaging_material_id' => ['required', 'integer', 'exists:packaging_materials,id'],
'supplier_id' => ['nullable', 'integer', 'exists:suppliers,id'],
'name' => ['required', 'string', 'max:255'],
'category' => ['required', Rule::in(['packaging', 'shipping'])],
'weight_grams' => ['nullable', 'numeric', 'min:0'],
'min_stock_alert' => ['nullable', 'integer', 'min:0'],
'url' => ['nullable', 'url', 'max:500'],
'product_id' => ['nullable', 'integer', 'exists:products,id'],
'active' => ['sometimes', 'boolean'],
];
}
protected function prepareForValidation(): void
{
$this->merge([
'active' => $this->boolean('active'),
'category' => trim((string) $this->input('category')),
'weight_grams' => $this->filled('weight_grams') ? reFormatNumber($this->input('weight_grams')) : null,
]);
foreach (['supplier_id', 'product_id', 'min_stock_alert'] as $key) {
if ($this->input($key) === '' || $this->input($key) === null) {
$this->merge([$key => null]);
}
}
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
class UpdatePackagingMaterialRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, string>>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'pos' => ['nullable', 'integer', 'min:0', 'max:255'],
];
}
protected function prepareForValidation(): void
{
if ($this->has('pos') && $this->input('pos') === '') {
$this->merge(['pos' => 0]);
}
}
}

View file

@ -0,0 +1,96 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Validator;
class UpdateStockEntryRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, mixed>>
*/
public function rules(): array
{
return [
'entry_type' => ['required', Rule::in(['ingredient', 'packaging', 'shipping'])],
'ingredient_id' => ['nullable', 'integer', 'exists:ingredients,id'],
'packaging_item_id' => ['nullable', 'integer', 'exists:packaging_items,id'],
'supplier_id' => ['required', 'integer', 'exists:suppliers,id'],
'location_id' => ['required', 'integer', 'exists:locations,id'],
'ordered_at' => ['required', 'date'],
'ordered_quantity' => ['required', 'numeric', 'min:0.000001'],
'quality_id' => ['nullable', 'integer', 'exists:material_qualities,id'],
'price_per_kg' => ['nullable', 'numeric', 'min:0'],
'price_total' => ['nullable', 'numeric', 'min:0'],
];
}
/**
* @return array<string, string>
*/
public function messages(): array
{
return [
'quality_id.required' => __('Bitte eine Rohstoffqualität wählen.'),
'price_per_kg.required' => __('Bitte den Netto-Preis pro kg angeben.'),
'price_total.required' => __('Bitte den Gesamtpreis netto angeben.'),
];
}
protected function prepareForValidation(): void
{
$this->merge([
'ordered_quantity' => reFormatNumber($this->input('ordered_quantity')),
'price_per_kg' => $this->filled('price_per_kg') ? reFormatNumber($this->input('price_per_kg')) : null,
'price_total' => $this->filled('price_total') ? reFormatNumber($this->input('price_total')) : null,
]);
}
public function withValidator(Validator $validator): void
{
$validator->after(function (Validator $validator): void {
$type = $this->input('entry_type');
if ($type === 'ingredient') {
if (empty($this->input('ingredient_id'))) {
$validator->errors()->add('ingredient_id', __('Bitte einen Inhaltsstoff wählen.'));
}
if (empty($this->input('quality_id'))) {
$validator->errors()->add('quality_id', __('Bitte eine Rohstoffqualität wählen.'));
}
if (! is_numeric($this->input('price_per_kg')) || (float) $this->input('price_per_kg') <= 0) {
$validator->errors()->add('price_per_kg', __('Bitte den Netto-Preis pro kg angeben.'));
}
} elseif (! empty($type)) {
if (empty($this->input('packaging_item_id'))) {
$validator->errors()->add('packaging_item_id', __('Bitte einen Verpackungsartikel wählen.'));
}
if (! is_numeric($this->input('price_total')) || (float) $this->input('price_total') <= 0) {
$validator->errors()->add('price_total', __('Bitte den Gesamtpreis netto angeben.'));
}
}
});
}
/**
* @return array<string, mixed>
*/
public function validatedPayload(): array
{
$data = $this->validated();
if (($data['entry_type'] ?? '') === 'ingredient') {
$data['packaging_item_id'] = null;
} else {
$data['ingredient_id'] = null;
$data['quality_id'] = null;
}
return $data;
}
}

View file

@ -0,0 +1,31 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
class UpdateSupplierCategoryRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, string>>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'pos' => ['nullable', 'integer', 'min:0', 'max:255'],
];
}
protected function prepareForValidation(): void
{
if ($this->has('pos') && $this->input('pos') === '') {
$this->merge(['pos' => 0]);
}
}
}

View file

@ -0,0 +1,39 @@
<?php
namespace App\Http\Requests\Inventory;
use Illuminate\Foundation\Http\FormRequest;
class UpdateSupplierRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, array<int, mixed>>
*/
public function rules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'url' => ['nullable', 'string', 'max:2048'],
'contact_person' => ['nullable', 'string', 'max:255'],
'email' => ['nullable', 'email', 'max:255'],
'phone' => ['nullable', 'string', 'max:100'],
'country_id' => ['required', 'integer', 'exists:countries,id'],
'notes' => ['nullable', 'string'],
'active' => ['sometimes', 'boolean'],
'supplier_category_ids' => ['nullable', 'array'],
'supplier_category_ids.*' => ['integer', 'exists:supplier_categories,id'],
];
}
protected function prepareForValidation(): void
{
$this->merge([
'active' => $this->boolean('active'),
]);
}
}

View file

@ -0,0 +1,46 @@
<?php
namespace App\Libraries;
use App\Libraries\CouponPDF;
use App\Models\Coupon;
use Storage;
class InvoicePDF{
protected $view;
protected $pdf;
public function __construct($view)
{
$this->view = $view;
}
public function create($data, $name='test.pdf', $output='stream', $path = false){
header('Content-type: text/html; charset=UTF-8') ;//chrome
//dd($data);
$pdf = app('dompdf.wrapper');
$pdf->getDomPDF();
$pdf->set_option("enable_php", true);
$pdf->loadView($this->view, $data);
$pdf->setPaper('A4', 'portrait');
if($output === 'stream'){
return $pdf->stream($name);
}
if($output === 'download'){
return $pdf->download($name);
}
if($output === 'save'){
if($path){
$pdf->save($path.$name);
return $path.$name;
}
}
}
}
?>

View file

@ -0,0 +1,188 @@
<?php
namespace App\Libraries;
//use FPDI in myMerge v2
//use FPDF;
//use FPDI;
class MyPDFMerger
{
private $_files; //['form.pdf'] ["1,2,4, 5-19"]
private $_fpdi;
public function __construct()
{
/* if(!class_exists("FPDF")) {
require_once(__DIR__.'/fpdf/fpdf.php');
}
if(!class_exists("FPDI")) {
require_once(__DIR__.'/fpdi/fpdi.php');
}*/
}
public function addPDF($filepath, $pages = 'all')
{
if (file_exists($filepath)) {
if (strtolower($pages) != 'all') {
$pages = $this->_rewritepages($pages);
}
$this->_files[] = array($filepath, $pages);
} else {
throw new \exception("Could not locate PDF on '$filepath'");
}
return $this;
}
public function myMerge($outputmode = 'browser', $outputpath = 'newfile.pdf', $theme = false)
{
if (!isset($this->_files) || !is_array($this->_files)): throw new \exception("No PDFs to merge."); endif;
$fpdi = new \setasign\Fpdi\Fpdi();
$first = 1;
//
//merger operations
foreach ($this->_files as $file) {
$filename = $file[0];
$filepages = $file[1];
$count = $fpdi->setSourceFile($filename);
//add the pages
if ($filepages == 'all') {
for ($i = 1; $i <= $count; $i++) {
$count = $fpdi->setSourceFile($filename);
$template = $fpdi->importPage($i);
$size = $fpdi->getTemplateSize($template);
$orientation = ($size['height'] > $size['width']) ? 'P' : 'L';
$fpdi->AddPage($orientation, array($size['width'], $size['height']));
if($theme){
$fpdi->setSourceFile(__DIR__ . '/../../public/pdf/'.$theme.'-'.$first.'.pdf');
if($first == 1){
$first = 2;
}
$backId = $fpdi->importPage(1);
$fpdi->useTemplate($backId);
}
$fpdi->useTemplate($template);
}
} else {
foreach ($filepages as $page) {
$count = $fpdi->setSourceFile($filename);
if (!$template = $fpdi->importPage($page)): throw new \exception("Could not load page '$page' in PDF '$filename'. Check that the page exists."); endif;
$size = $fpdi->getTemplateSize($template);
$orientation = ($size['h'] > $size['w']) ? 'P' : 'L';
$fpdi->AddPage($orientation, array($size['w'], $size['h']));
if($theme){
$fpdi->setSourceFile(__DIR__ . '/../../public/pdf/'.$theme.'-'.$first.'.pdf');
if($first == 1){
$first = 2;
}
$backId = $fpdi->importPage(1);
$fpdi->useTemplate($backId);
}
$fpdi->useTemplate($template);
}
}
//after first file (invoice) on bpaper
$slug = false;
}
//output operations
$mode = $this->_switchmode($outputmode);
if ($mode == 'S') {
return $fpdi->Output($outputpath, 'S');
} else {
if ($fpdi->Output($outputpath, $mode) == '') {
return true;
} else {
throw new \exception("Error outputting PDF to '$outputmode'.");
return false;
}
}
}
/**
* FPDI uses single characters for specifying the output location. Change our more descriptive string into proper format.
* @param $mode
* @return Character
*/
private function _switchmode($mode)
{
switch (strtolower($mode)) {
case 'download':
return 'D';
break;
case 'browser':
return 'I';
break;
case 'file':
return 'F';
break;
case 'string':
return 'S';
break;
default:
return 'I';
break;
}
}
/**
* Takes our provided pages in the form of 1,3,4,16-50 and creates an array of all pages
* @param $pages
* @return array
* @throws exception
*/
private function _rewritepages($pages)
{
$pages = str_replace(' ', '', $pages);
$part = explode(',', $pages);
//parse hyphens
foreach ($part as $i) {
$ind = explode('-', $i);
if (count($ind) == 2) {
$x = $ind[0]; //start page
$y = $ind[1]; //end page
if ($x > $y): throw new \exception("Starting page, '$x' is greater than ending page '$y'.");
return false; endif;
//add middle pages
while ($x <= $y): $newpages[] = (int)$x;
$x++; endwhile;
} else {
$newpages[] = (int)$ind[0];
}
}
return $newpages;
}
}
/*
$pdf = new PDFMerger;
$pdf->addPDF('samplepdfs/one.pdf', '1, 3, 4')
->addPDF('samplepdfs/two.pdf', '1-2')
->addPDF('samplepdfs/three.pdf', 'all')
->merge('file', 'samplepdfs/TEST2.pdf');
//REPLACE 'file' WITH 'browser', 'download', 'string', or 'file' for output options
//You do not need to give a file path for browser, string, or download - just the name.
*/

View file

@ -31,7 +31,11 @@ class MailCheckout extends Mailable
$this->mode = $mode;
if($this->txaction === 'paid'){
$this->subject = __('email.checkout_subject_paid')." ";
if($this->shopping_payment->clearingtype === 'non')
$this->subject = __('email.checkout_subject_non_paid')." ";
else{
$this->subject = __('email.checkout_subject_paid')." ";
}
}elseif($this->txaction === 'extern'){
$this->subject = __('email.checkout_subject_extern').": ";
$this->subject .= $shopping_order->member->account->m_first_name." ".$shopping_order->member->account->m_last_name." - ";
@ -45,7 +49,6 @@ class MailCheckout extends Mailable
}*/
}
public function build()
{
$salutation = __('email.hello').",";
@ -64,8 +67,8 @@ class MailCheckout extends Mailable
'greetings' => __('email.greetings'),
'sender' => __('email.sender'),
'send_link' => $this->send_link,
'url' => Util::getMyMivitaUrl(),
'button' => Util::getMyMivitaUrl(false),
'url' => Util::getMyUrl(),
'button' => Util::getMyUrl(false),
'mode' => $this->mode
]);
}else{
@ -82,6 +85,5 @@ class MailCheckout extends Mailable
'mode' => $this->mode
]);
}
}
}

63
app/Mail/MailLog.php Normal file
View file

@ -0,0 +1,63 @@
<?php
namespace App\Mail;
use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
class MailLog extends Mailable
{
use Queueable, SerializesModels;
protected $channel;
protected $context;
protected $message;
protected $data;
public $subject;
public function __construct($channel, $context, $message, $data)
{
$this->channel = $channel;
$this->context = $context;
$this->message = $message;
$this->data = $data;
$this->subject = 'mivita Log';
}
public function build()
{
$title = 'Log: '.$this->channel.' '.$this->context;
//make Data readable
$this->data = json_encode($this->data, JSON_PRETTY_PRINT);
$content = "";
$content .= "\n";
$content .= "Channel: ".$this->channel."\n";
$content .= "Context: ".$this->context."\n";
if(\Auth::check()){
$content .= "From User: ".\Auth::user()->id." | ".\Auth::user()->email."\n";
}
$content .= "\n";
$content .= "Message: ".$this->message."\n";
$content .= "\n";
$content .= "Data: ".$this->data."\n";
$content .= "\n";
$content .= "\n";
$content .= "Time: ".now()->format("d.m.Y H:i");
$content .= "\n";
$content .= request()->header('User-Agent');
return $this->view('emails.sys')->with([
'title' => $title,
'content' => $content,
]);
}
}

87
app/Mail/MailLogistic.php Normal file
View file

@ -0,0 +1,87 @@
<?php
namespace App\Mail;
use App\Models\ShoppingOrder;
use App\Services\Invoice;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Storage;
class MailLogistic extends Mailable
{
use Queueable, SerializesModels;
protected $shopping_order;
public $subject;
public function __construct(ShoppingOrder $shopping_order)
{
$this->shopping_order = $shopping_order;
$name = $shopping_order->shopping_user->billing_firstname.' '.$shopping_order->shopping_user->billing_lastname;
$company = $shopping_order->shopping_user->billing_company ?? '';
$hasWhiteLabel = $shopping_order->user_white_label || $shopping_order->hasWhitelabelProducts();
$this->subject = 'Partner';
if ($hasWhiteLabel) {
// Bei allen, die ein eigenes Logo haben
$this->subject .= ' (mit Logo)';
} else {
// Bei allen, die kein Tattoostudio sind
$this->subject = ' - ';
}
if ($shopping_order->shopping_user->same_as_billing) {
// Rechnungsadresse und Lieferadresse sind gleich
$this->subject = '';
} else {
// hat eine andere Lieferadresse
$this->subject = ' Lieferadresse';
}
$this->subject .= ' '.$company.' ('.$name.')';
}
public function build()
{
$title = false;
$copy1line = false;
$filename = Invoice::getFilename($this->shopping_order);
$path = Invoice::getDownloadPath($this->shopping_order);
if (! Storage::disk('public')->exists($path)) {
return;
}
$file = Storage::disk('public')->path($path);
$mime = Storage::disk('public')->mimeType($path);
$mail = $this->view('emails.logistic')->with([
'title' => $title,
'copy1line' => $copy1line,
])->attach($file, [
'as' => $filename,
'mime' => $mime,
]);
// Wenn mindestens ein White-Label-Produkt enthalten ist, wird der Lieferschein (Etikett-Infos) mit angehängt
$hasWhiteLabel = $this->shopping_order->user_white_label || $this->shopping_order->hasWhitelabelProducts();
if ($hasWhiteLabel) {
$filenameDelivery = Invoice::getDeliveryFilename($this->shopping_order);
$pathDelivery = Invoice::getDownloadPathDelivery($this->shopping_order);
if (! Storage::disk('public')->exists($pathDelivery)) {
return;
}
$fileDelivery = Storage::disk('public')->path($pathDelivery);
$mimeDelivery = Storage::disk('public')->mimeType($pathDelivery);
$mail->attach($fileDelivery, [
'as' => $filenameDelivery,
'mime' => $mimeDelivery,
]); // attach file;
}
return $mail;
}
}

59
app/Mail/MailLogitic.php Normal file
View file

@ -0,0 +1,59 @@
<?php
namespace App\Mail;
use App\User;
use App\Services\Invoice;
use App\Models\ShoppingOrder;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Storage;
use Illuminate\Contracts\Queue\ShouldQueue;
class MailLogistic extends Mailable
{
use Queueable, SerializesModels;
protected $shopping_order;
public $subject;
public function __construct(ShoppingOrder $shopping_order)
{
$this->shopping_order = $shopping_order;
if($shopping_order->user_white_label){
//Bei allen, die ein eigenes Logo haben
$this->subject = 'Partner (mit Logo) - Firma (Vorname Nachname)';
}else{
//Bei allen, die kein Tattoostudio sind
$this->subject = 'Partner - Firma (Vorname Nachname)';
}
}
public function build()
{
$title = false;
$copy1line = false;
$filename = Invoice::getFilename($this->shopping_order);
$path = Invoice::getDownloadPath($this->shopping_order);
if (!Storage::disk('public')->exists($path)) {
return;
}
$file = Storage::disk('public')->path($path);
$mime = Storage::disk('public')->mimeType($path);
return $this->view('emails.blank')->with([
'title' => $title,
'copy1line' => $copy1line,
])->attach($file,[
'as' => $filename,
'mime' => $mime,
]); // attach file;
}
}

View file

@ -12,14 +12,14 @@ class MailVerifyAccount extends Mailable
use Queueable, SerializesModels;
protected $confirmation_code;
protected $user;
protected $userObj;
public $subject;
public function __construct($confirmation_code, User $user)
public function __construct($confirmation_code, $userObj)
{
$this->confirmation_code = $confirmation_code;
$this->user = $user;
$this->userObj = $userObj;
$this->subject = __('email.email_verify');
}
@ -27,11 +27,11 @@ class MailVerifyAccount extends Mailable
public function build()
{
$salutation = __('email.salutation').",";
if($this->user->account){
if($this->user->account->salutation === "mr"){
$salutation = __('email.dear_sir')." ".$this->user->account->first_name.",";
if($this->userObj){
if($this->userObj->salutation === "mr"){
$salutation = __('email.dear_sir')." ".$this->userObj->first_name.",";
}else{
$salutation = __('email.dear_mrs')." ".$this->user->account->first_name.",";
$salutation = __('email.dear_mrs')." ".$this->userObj->first_name.",";
}
}
return $this->view('emails.auth')->with([

View file

@ -0,0 +1,60 @@
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\Services\Util;
class PaymentReminderEmail extends Mailable
{
use Queueable, SerializesModels;
protected $emailSubject;
protected $message;
protected $order;
public $data;
/**
* Erstellt eine neue PaymentReminderEmail Instanz
*
* @param string $subject
* @param string $message
* @param object|null $user
* @param object|null $order
* @param float|null $paymentAmount
* @param string|null $dueDate
* @param string|null $paymentUrl
*/
public function __construct($subject, $message, $order = null)
{
$this->emailSubject = $subject;
$this->message = $message;
$this->order = $order;
}
/**
* Baut die E-Mail
*
* @return $this
*/
public function build()
{
$paymentUrl = route('user_myorder_detail', ['id' => $this->order->id]);
$buttonText = __('email.my_orders') ?: 'Meine Bestellungen';
return $this->subject($this->emailSubject)
->view('emails.payment_reminder')
->with([
'content' => $this->message,
'url' => $paymentUrl,
'button' => $buttonText,
]);
}
}

View file

@ -2,6 +2,7 @@
namespace App\Models;
use App\Services\Util;
use Illuminate\Database\Eloquent\Model;
/**
@ -25,39 +26,66 @@ use Illuminate\Database\Eloquent\Model;
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Attribute wherePos($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Attribute whereTransName($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Attribute whereUpdatedAt($value)
* @mixin \Eloquent
* @property string|null $slug
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Attribute whereSlug($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Attribute newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Attribute newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Attribute query()
* @property-read int|null $childrens_count
* @property int $attribute_type_id
* @property string|null $value
* @property-read \App\Models\AttributeType $attribute_type
* @method static \Illuminate\Database\Eloquent\Builder|Attribute whereAttributeTypeId($value)
* @method static \Illuminate\Database\Eloquent\Builder|Attribute whereValue($value)
* @mixin \Eloquent
*/
class Attribute extends Model
{
protected $table = 'attributes';
protected $casts = ['trans_name' => 'array'];
protected $fillable = [
'parent_id', 'name', 'pos', 'active',
protected $casts = [
'parent_id' => 'int',
'pos' => 'int',
'active' => 'bool',
'trans_name' => 'array',
];
protected $fillable = [
'parent_id',
'attribute_type_id',
'name',
'value',
'trans_name',
'pos',
'active',
'slug'
];
public function attribute_type()
{
return $this->belongsTo(AttributeType::class, 'attribute_type_id');
}
public function parent()
{
return $this->belongsTo('App\Models\Attribute', 'parent_id');
return $this->belongsTo(Attribute::class, 'parent_id');
}
public function childrens()
{
return $this->hasMany('App\Models\Attribute', 'parent_id', 'id');
return $this->hasMany(Attribute::class, 'parent_id', 'id');
}
public function setPosAttribute($value){
$this->attributes['pos'] = is_numeric($value) ? $value : null;
}
public function getFormattedValue()
{
// return isset($this->attributes['value']) ? Util::formatNumber($this->attributes['value']) : "";
}
public function getLang($key)
{
$lang = \App::getLocale();

View file

@ -0,0 +1,111 @@
<?php
/**
* Created by Reliese Model.
*/
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
/**
* Class AttributeType
*
* @property int $id
* @property int|null $parent_id
* @property string $name
* @property string|null $trans_name
* @property int|null $pos
* @property bool $active
* @property string $slug
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
* @property Attribute|null $attribute
* @property Collection|Attribute[] $attributes
* @package App\Models
* @property string|null $description
* @property-read Collection<int, \App\Models\Attribute> $childrens
* @property-read int|null $childrens_count
* @property-read \App\Models\Attribute|null $parent
* @method static \Illuminate\Database\Eloquent\Builder|AttributeType newModelQuery()
* @method static \Illuminate\Database\Eloquent\Builder|AttributeType newQuery()
* @method static \Illuminate\Database\Eloquent\Builder|AttributeType query()
* @method static \Illuminate\Database\Eloquent\Builder|AttributeType whereActive($value)
* @method static \Illuminate\Database\Eloquent\Builder|AttributeType whereCreatedAt($value)
* @method static \Illuminate\Database\Eloquent\Builder|AttributeType whereDescription($value)
* @method static \Illuminate\Database\Eloquent\Builder|AttributeType whereId($value)
* @method static \Illuminate\Database\Eloquent\Builder|AttributeType whereName($value)
* @method static \Illuminate\Database\Eloquent\Builder|AttributeType whereParentId($value)
* @method static \Illuminate\Database\Eloquent\Builder|AttributeType wherePos($value)
* @method static \Illuminate\Database\Eloquent\Builder|AttributeType whereSlug($value)
* @method static \Illuminate\Database\Eloquent\Builder|AttributeType whereTransName($value)
* @method static \Illuminate\Database\Eloquent\Builder|AttributeType whereUpdatedAt($value)
* @mixin \Eloquent
*/
class AttributeType extends Model
{
protected $table = 'attribute_types';
protected $casts = [
'parent_id' => 'int',
'pos' => 'int',
'active' => 'bool',
'trans_name' => 'array'
];
protected $fillable = [
'parent_id',
'name',
'description',
'trans_name',
'pos',
'active',
'slug'
];
public function parent()
{
return $this->belongsTo(Attribute::class, 'parent_id');
}
public function childrens()
{
return $this->hasMany(Attribute::class, 'parent_id', 'id');
}
public function setPosAttribute($value){
$this->attributes['pos'] = is_numeric($value) ? $value : null;
}
public function getLang($key)
{
$lang = \App::getLocale();
if ($lang == 'de') {
return $this->{$key};
}
$trans = $this->getTrans($key, $lang);
if (!$trans || $trans == '') {
return $this->{$key};
}
return $trans;
}
public function getTrans($key, $lang)
{
$key = 'trans_' . $key;
if (!empty($this->{$key}[$lang])) {
return $this->{$key}[$lang];
}
}
public function getTranNames()
{
$ret = "";
foreach ((array) $this->trans_name as $value){
$ret .= $value.', ';
}
return rtrim($ret, ', ');
}
}

View file

@ -2,6 +2,8 @@
namespace App\Models;
use App\Services\Type;
use App\Models\Product;
use Illuminate\Database\Eloquent\Model;
use Cviebrock\EloquentSluggable\Sluggable;
@ -26,7 +28,6 @@ use Cviebrock\EloquentSluggable\Sluggable;
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category wherePos($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category whereTransName($value)
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category whereUpdatedAt($value)
* @mixin \Eloquent
* @property string|null $slug
* @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\ProductCategory[] $product_categories
* @method static \Illuminate\Database\Eloquent\Builder|\App\Models\Category findSimilarSlugs($attribute, $config, $slug)
@ -46,6 +47,9 @@ use Cviebrock\EloquentSluggable\Sluggable;
* @property-read \App\Models\IqImage|null $iq_image
* @property-read int|null $product_categories_count
* @method static \Illuminate\Database\Eloquent\Builder|Category withUniqueSlugConstraints(\Illuminate\Database\Eloquent\Model $model, string $attribute, array $config, string $slug)
* @property array|null $show_on
* @method static \Illuminate\Database\Eloquent\Builder|Category whereShowOn($value)
* @mixin \Eloquent
*/
class Category extends Model
{
@ -53,13 +57,13 @@ class Category extends Model
protected $table = 'categories';
protected $casts = ['trans_name' => 'array', 'trans_headline' => 'array'];
protected $casts = ['trans_name' => 'array', 'trans_headline' => 'array', 'show_on' => 'array'];
protected $fillable = [
'parent_id', 'name', 'headline', 'pos', 'active',
'parent_id', 'name', 'headline', 'pos', 'active', 'show_on'
];
public function sluggable()
public function sluggable(): array
{
return [
'slug' => [
@ -133,4 +137,21 @@ class Category extends Model
return rtrim($ret, ', ');
}
public function getShowOnTypes($seperator = false){
$ret = [];
if($this->show_on && is_array($this->show_on)){
foreach($this->show_on as $show){
$ret[] = isset(Type::$showONs[$show]) ? Type::$showONs[$show] : '-';
}
}
return $seperator ? implode($seperator, $ret) : $ret;
}
public function getProductsCountOn($show_on = ['8']){
$category_id = $this->id;
return Product::where('active', true)->whereJsonContains('show_on', $show_on)
->whereHas('categories', function ($query) use ($category_id) {
$query->where('category_id', $category_id); //
})->orderBy('pos', 'ASC')->count();
}
}

Some files were not shown because too many files have changed in this diff Show more