Skip to content

Commit a6cbac7

Browse files
Comit inicial da base do Tenant
1 parent 684e26e commit a6cbac7

File tree

2,215 files changed

+140602
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

2,215 files changed

+140602
-0
lines changed

.editorconfig

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
root = true
2+
3+
[*]
4+
charset = utf-8
5+
end_of_line = lf
6+
indent_size = 4
7+
indent_style = space
8+
insert_final_newline = true
9+
trim_trailing_whitespace = true
10+
11+
[*.md]
12+
trim_trailing_whitespace = false
13+
14+
[*.{yml,yaml}]
15+
indent_size = 2
16+
17+
[docker-compose.yml]
18+
indent_size = 4

.env.example

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
APP_NAME="Core Tenant"
2+
APP_ENV=local
3+
APP_KEY=
4+
APP_DEBUG=true
5+
APP_TIMEZONE='America/Sao_Paulo'
6+
APP_URL=http://localhost
7+
8+
APP_LOCALE=pt_BR
9+
APP_FALLBACK_LOCALE=en
10+
APP_FAKER_LOCALE=en_US
11+
12+
APP_MAINTENANCE_DRIVER=file
13+
APP_MAINTENANCE_STORE=database
14+
15+
BCRYPT_ROUNDS=12
16+
17+
LOG_CHANNEL=stack
18+
LOG_STACK=single
19+
LOG_DEPRECATIONS_CHANNEL=null
20+
LOG_LEVEL=debug
21+
22+
DB_CONNECTION=mysql
23+
DB_HOST=mysql
24+
DB_PORT=3306
25+
DB_DATABASE=db_core_tenant
26+
DB_USERNAME=administrator
27+
DB_PASSWORD=Administrator123
28+
29+
30+
SESSION_DRIVER=database
31+
SESSION_LIFETIME=120
32+
SESSION_ENCRYPT=false
33+
SESSION_PATH=/
34+
SESSION_DOMAIN=null
35+
36+
BROADCAST_CONNECTION=log
37+
FILESYSTEM_DISK=public
38+
FILAMENT_FILESYSTEM_DISK=public
39+
QUEUE_CONNECTION=sync
40+
CACHE_DRIVER=database
41+
42+
CACHE_STORE=database
43+
CACHE_PREFIX=
44+
45+
MEMCACHED_HOST=127.0.0.1
46+
47+
REDIS_CLIENT=redis
48+
REDIS_HOST=redis
49+
REDIS_PASSWORD=null
50+
REDIS_PORT=6379
51+
52+
MAIL_MAILER=smtp
53+
MAIL_HOST=mailpit
54+
MAIL_PORT=1025
55+
MAIL_USERNAME=null
56+
MAIL_PASSWORD=null
57+
MAIL_ENCRYPTION=null
58+
MAIL_FROM_ADDRESS="[email protected]"
59+
MAIL_FROM_NAME="${APP_NAME}"
60+
61+
AWS_ACCESS_KEY_ID=
62+
AWS_SECRET_ACCESS_KEY=
63+
AWS_DEFAULT_REGION=us-east-1
64+
AWS_BUCKET=
65+
AWS_USE_PATH_STYLE_ENDPOINT=false
66+
67+
VITE_APP_NAME="${APP_NAME}"
68+
69+
CASHIER_MODEL=App\Models\Organization
70+
CASHIER_CURRENCY=brl
71+
CASHIER_CURRENCY_LOCALE=br
72+
73+
#Keys autenticação Laravel/Stripe
74+
STRIPE_KEY=pk_test_51IoE1ML3qJV3bURY8oq6EM7F5gHEix5CWcuU1J5ABHmSfahE2KzoGbfAe8JC9aSxk4XHDH1CaqJFrzgWxzWfr6B800xSVupXqU
75+
STRIPE_SECRET=sk_test_51IoE1ML3qJV3bURYQQ3AxGqQOfpI1gaZdEOkBkALvo4uksiZEk48sVd1vn6Bdmcm5zcqvmo7IwexpzHh7WAV8JuD00H7sXpSIH
76+
STRIPE_WEBHOOK_SECRET=whsec_cca778295a44cdb01b99a98d48c594b934c119bf8e8c5d99f4d39e74955991fa

.gitattributes

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
* text=auto eol=lf
2+
3+
*.blade.php diff=html
4+
*.css diff=css
5+
*.html diff=html
6+
*.md diff=markdown
7+
*.php diff=php
8+
9+
/.github export-ignore
10+
CHANGELOG.md export-ignore
11+
.styleci.yml export-ignore

.gitignore

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/.phpunit.cache
2+
/node_modules
3+
/public/build
4+
/public/hot
5+
/public/storage
6+
/storage/*.key
7+
/storage/pail
8+
/vendor
9+
.env
10+
.env.backup
11+
.env.production
12+
.phpactor.json
13+
.phpunit.result.cache
14+
Homestead.json
15+
Homestead.yaml
16+
auth.json
17+
npm-debug.log
18+
yarn-error.log
19+
/.fleet
20+
/.idea
21+
/.nova
22+
/.vscode
23+
/.zed
24+
.docker

Dockerfile

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
FROM php:8.3-fpm
2+
3+
# Arguments defined in docker-compose.yml
4+
ARG user=wallace
5+
ARG uid=1000
6+
7+
# Install system dependencies
8+
RUN apt-get update && apt-get install -y \
9+
git \
10+
curl \
11+
libpng-dev \
12+
libonig-dev \
13+
libxml2-dev \
14+
libzip-dev \
15+
unzip \
16+
gnupg \
17+
ca-certificates \
18+
lsb-release
19+
20+
# Clear cache
21+
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
22+
23+
# Add Node.js repository and install Node.js & NPM
24+
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
25+
apt-get install -y nodejs && \
26+
npm install -g npm@latest
27+
28+
# Install PHP extensions
29+
RUN docker-php-ext-install pdo_mysql mbstring exif pcntl bcmath gd sockets intl zip
30+
31+
# Get latest Composer
32+
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
33+
34+
# Create system user to run Composer and Artisan Commands
35+
RUN useradd -G www-data,root -u $uid -d /home/$user $user
36+
RUN mkdir -p /home/$user/.composer && \
37+
chown -R $user:$user /home/$user
38+
39+
# Install redis
40+
RUN pecl install -o -f redis \
41+
&& rm -rf /tmp/pear \
42+
&& docker-php-ext-enable redis
43+
44+
# Install Stripe CLI
45+
RUN curl -s https://packages.stripe.dev/api/security/keypair/stripe-cli-gpg/public | gpg --dearmor > /usr/share/keyrings/stripe.gpg
46+
RUN echo "deb [signed-by=/usr/share/keyrings/stripe.gpg] https://packages.stripe.dev/stripe-cli-debian-local stable main" > /etc/apt/sources.list.d/stripe.list
47+
RUN apt-get update -y && apt-get install -y stripe
48+
49+
# Set working directory
50+
WORKDIR /var/www
51+
52+
# Change to non-root user
53+
USER $user

app/Data/Cashier/Plan.php

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Data\Cashier;
6+
7+
readonly class Plan
8+
{
9+
private function __construct(
10+
private string $type,
11+
private string $name,
12+
private string $shortDescription,
13+
private string $productId,
14+
private array $rawPrices,
15+
private array $features
16+
) {
17+
}
18+
19+
public static function fromArray(array $data, string $key): self
20+
{
21+
22+
23+
return new self(
24+
type: $data['type'] ?? $key,
25+
name: $data['name'],
26+
shortDescription: $data['short_description'],
27+
productId: $data['product_id'],
28+
rawPrices: $data['prices'],
29+
features: $data['features']
30+
);
31+
}
32+
33+
public function type(): string
34+
{
35+
return $this->type;
36+
}
37+
38+
public function name(): string
39+
{
40+
return $this->name;
41+
}
42+
43+
public function shortDescription(): string
44+
{
45+
return $this->shortDescription;
46+
}
47+
48+
public function productId(): string
49+
{
50+
return $this->productId;
51+
}
52+
53+
/**
54+
* @return array<Price>
55+
*/
56+
public function prices(): array
57+
{
58+
return array_map(
59+
fn (array $price, string $key) => Price::fromArray($price, $key),
60+
$this->rawPrices,
61+
array_keys($this->rawPrices)
62+
);
63+
}
64+
65+
public function features(): array
66+
{
67+
return $this->features;
68+
}
69+
}

app/Data/Cashier/Price.php

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Data\Cashier;
6+
7+
readonly class Price
8+
{
9+
private function __construct(
10+
private string $period,
11+
private string $periodo,
12+
private string $id,
13+
private int $price
14+
) {
15+
}
16+
17+
public static function fromArray(array $data, string $key): self
18+
{
19+
return new self(
20+
period: $data['period'] ?? $key,
21+
periodo: $data['periodo'] ?? $key,
22+
id: $data['id'],
23+
price: $data['price']
24+
);
25+
}
26+
27+
public function period(): string
28+
{
29+
return $this->period;
30+
}
31+
32+
33+
public function periodo(): string
34+
{
35+
return $this->periodo;
36+
}
37+
38+
public function id(): string
39+
{
40+
return $this->id;
41+
}
42+
43+
public function price(): int
44+
{
45+
return $this->price;
46+
}
47+
}

app/Data/Cashier/Stripe.php

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Data\Cashier;
6+
7+
use App\Models\Organization;
8+
use function App\Support\tenant;
9+
10+
use Filament\Pages\Dashboard;
11+
use Illuminate\Support\Arr;
12+
use InvalidArgumentException;
13+
14+
readonly class Stripe
15+
{
16+
private function __construct(
17+
private int $trialDays,
18+
private bool $allowPromotionCodes,
19+
private array $billedPeriods,
20+
private array $plans
21+
) {
22+
}
23+
24+
public static function fromConfig(): self
25+
{
26+
return new self(
27+
trialDays: config('stripe.trial_days'),
28+
allowPromotionCodes: config('stripe.allow_promotion_codes'),
29+
billedPeriods: config('stripe.billed_periods'),
30+
plans: config('stripe.plans'),
31+
);
32+
}
33+
34+
public function trialDays(): int
35+
{
36+
return $this->trialDays;
37+
}
38+
39+
public function allowPromotionCodes(): bool
40+
{
41+
return $this->allowPromotionCodes;
42+
}
43+
44+
/**
45+
* @return array<Plan>
46+
*/
47+
public function plans(): array
48+
{
49+
return array_map(
50+
fn (array $plan, string $key) => Plan::fromArray($plan, $key),
51+
$this->plans,
52+
array_keys($this->plans)
53+
);
54+
}
55+
56+
public function billedPeriods(): array
57+
{
58+
return $this->billedPeriods;
59+
}
60+
61+
public function checkoutUrl(string $period): void
62+
{
63+
64+
$plan = Arr::first($this->plans());
65+
66+
if (! $plan) {
67+
throw new InvalidArgumentException('Plan not configured');
68+
}
69+
70+
/** @var Price|null $price */
71+
$price = collect($plan->prices())
72+
->first(fn (Price $price) => $price->period() === $period);
73+
74+
if (! $price) {
75+
throw new InvalidArgumentException("Price not found for period: {$period}");
76+
}
77+
78+
$tenant = tenant(Organization::class);
79+
80+
$tenant->newSubscription($plan->type(), $price->id())
81+
->checkout([
82+
'success_url' => Dashboard::getUrl(),
83+
'cancel_url' => Dashboard::getUrl(),
84+
])
85+
->redirect();
86+
}
87+
}

0 commit comments

Comments
 (0)