updateeeeee
This commit is contained in:
parent
0c758749e0
commit
ca9819a436
12 changed files with 214 additions and 156 deletions
|
@ -10,7 +10,7 @@ use Doctrine\Migrations\AbstractMigration;
|
|||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class Version20250609175837 extends AbstractMigration
|
||||
final class Version20250610173233 extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
|
@ -23,20 +23,11 @@ final class Version20250609175837 extends AbstractMigration
|
|||
$this->addSql(<<<'SQL'
|
||||
CREATE TABLE drink_type (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
|
||||
, updated_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
|
||||
, name VARCHAR(255) NOT NULL, description CLOB DEFAULT NULL, desired_stock INTEGER NOT NULL)
|
||||
, name VARCHAR(255) NOT NULL, description CLOB DEFAULT NULL, wanted_stock INTEGER NOT NULL, current_stock INTEGER NOT NULL)
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE UNIQUE INDEX UNIQ_841484B15E237E06 ON drink_type (name)
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE TABLE inventory_record (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, drink_type_id INTEGER NOT NULL, quantity INTEGER NOT NULL, timestamp DATETIME NOT NULL --(DC2Type:datetime_immutable)
|
||||
, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
|
||||
, updated_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
|
||||
, CONSTRAINT FK_9BE8033AE7E8D8A1 FOREIGN KEY (drink_type_id) REFERENCES drink_type (id) NOT DEFERRABLE INITIALLY IMMEDIATE)
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE INDEX IDX_9BE8033AE7E8D8A1 ON inventory_record (drink_type_id)
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
CREATE TABLE "order" (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, created_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
|
||||
, updated_at DATETIME NOT NULL --(DC2Type:datetime_immutable)
|
||||
|
@ -73,9 +64,6 @@ final class Version20250609175837 extends AbstractMigration
|
|||
$this->addSql(<<<'SQL'
|
||||
DROP TABLE drink_type
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
DROP TABLE inventory_record
|
||||
SQL);
|
||||
$this->addSql(<<<'SQL'
|
||||
DROP TABLE "order"
|
||||
SQL);
|
6
public/assets/css/bootstrap.min.css
vendored
6
public/assets/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
|
@ -29,45 +29,145 @@
|
|||
}
|
||||
}
|
||||
|
||||
/* Light Mode (Default) */
|
||||
/*
|
||||
* =================================================================================================
|
||||
* ✨💅 GAY, SLAY & FABULOUS THEME 💅✨
|
||||
*
|
||||
* A Bootstrap override that's unapologetically queer, vibrant, and readable.
|
||||
* Because your website deserves to be as iconic as you are.
|
||||
*
|
||||
* Designed with love, glitter, and a whole lot of sass.
|
||||
* =================================================================================================
|
||||
*/
|
||||
|
||||
:root {
|
||||
--bs-primary: #ff47a3; /* Hot Pink */
|
||||
--bs-secondary: #7367f0; /* Lavender */
|
||||
--bs-success: #53e69d; /* Minty Green */
|
||||
--bs-info: #51caff; /* Sky Blue */
|
||||
--bs-warning: #ffd53e; /* Sunshine Yellow */
|
||||
--bs-danger: #ff5666; /* Coral Red */
|
||||
--bs-light: #fff7fa; /* Almost-white Pink */
|
||||
--bs-dark: #3b233d; /* Deep Purple */
|
||||
/* 🌈✨ The Main Attraction: A Vibrant & Proud Palette ✨🌈 */
|
||||
--bs-red: #FF3860; /* 🍒 Cherry Pop Realness */
|
||||
--bs-orange: #FF9F43; /* 🍊 Tangerine Dream Queen */
|
||||
--bs-yellow: #FFE156; /* 🌟 Superstar Spotlight */
|
||||
--bs-green: #34C759; /* 🌿 Growth & chosen family */
|
||||
--bs-teal: #20c997; /* 🧜♀️ Mermaid's Grotto */
|
||||
--bs-cyan: #4ED6FF; /* 🧊 Iced Genderfluid */
|
||||
--bs-blue: #5AC8FA; /* 🦋 Blue Bi You */
|
||||
--bs-indigo: #6C63FF; /* 🦄 Unicorn Energy */
|
||||
--bs-purple: #AF52DE; /* 💜 Violets for Visibility */
|
||||
--bs-pink: #FF6F91; /* 💖 Queerberry Kiss */
|
||||
|
||||
/* Quirk it up further */
|
||||
--bs-body-bg: #fff7fa;
|
||||
--bs-body-color: #3b233d;
|
||||
--bs-link-color: #ff47a3;
|
||||
--bs-link-hover-color: #7367f0;
|
||||
--bs-border-color: #ffb8e1;
|
||||
/* 💅 Neutrals That Are Anything But Neutral 💅 */
|
||||
--bs-black: #1A202C; /* 🕶️ Midnight Manifesto */
|
||||
--bs-white: #F8F7FF; /* ☁️ Cloud Nine Comfort */
|
||||
--bs-gray: #A0AEC0; /* 🌫️ Foggy Festival Morning */
|
||||
--bs-gray-dark: #2D3748; /* 🖤 Emo Afterparty */
|
||||
--bs-gray-100: #F7FAFC;
|
||||
--bs-gray-200: #EDF2F7;
|
||||
--bs-gray-300: #E2E8F0;
|
||||
--bs-gray-400: #CBD5E1;
|
||||
--bs-gray-500: #A0AEC0;
|
||||
--bs-gray-600: #718096;
|
||||
--bs-gray-700: #4A5568;
|
||||
--bs-gray-800: #2D3748;
|
||||
--bs-gray-900: #1A202C;
|
||||
|
||||
/* 💖 Semantic Roles: Give Every Color a Job 💖 */
|
||||
--bs-primary: var(--bs-indigo); /* Main Character Energy */
|
||||
--bs-secondary: var(--bs-pink); /* Sassy Sidekick */
|
||||
--bs-success: var(--bs-green); /* Yas, Queen! (Success) */
|
||||
--bs-info: var(--bs-cyan); /* The Tea (Information) */
|
||||
--bs-warning: var(--bs-orange); /* Hun, Be Careful (Warning) */
|
||||
--bs-danger: var(--bs-red); /* Not Today, Satan (Danger) */
|
||||
--bs-light: var(--bs-gray-100); /* Daytime Disco */
|
||||
--bs-dark: var(--bs-gray-900); /* Velvet Rope */
|
||||
|
||||
/* 📖 Fonts with Personality 📖 */
|
||||
/* Recommendation: Import "Quicksand" and "Fira Mono" from Google Fonts for the full effect! */
|
||||
--bs-font-sans-serif: "Quicksand", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--bs-font-monospace: "Fira Mono", SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
||||
|
||||
/* ✨ The Gradient That Slays ✨ */
|
||||
--bs-gradient: linear-gradient(93deg, var(--bs-indigo), var(--bs-pink) 50%, var(--bs-orange));
|
||||
|
||||
/* 🎨 Core Styles for a Flawless Look 🎨 */
|
||||
--bs-body-color: var(--bs-gray-800);
|
||||
--bs-body-bg: var(--bs-white);
|
||||
--bs-emphasis-color: var(--bs-black);
|
||||
--bs-secondary-color: rgba(45, 55, 72, 0.75);
|
||||
--bs-secondary-bg: var(--bs-gray-200);
|
||||
--bs-tertiary-color: rgba(45, 55, 72, 0.5);
|
||||
--bs-tertiary-bg: var(--bs-gray-100);
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: var(--bs-primary);
|
||||
--bs-link-hover-color: var(--bs-purple);
|
||||
--bs-code-color: var(--bs-pink);
|
||||
--bs-highlight-bg: #fff9c4; /* A soft, buttery highlight */
|
||||
--bs-border-color: var(--bs-gray-300);
|
||||
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
|
||||
--bs-border-radius: 0.5rem; /* A little softer, a little friendlier */
|
||||
--bs-border-radius-lg: 0.75rem;
|
||||
--bs-border-radius-sm: 0.25rem;
|
||||
--bs-box-shadow: 0 0.25rem 1.5rem rgba(45, 55, 72, 0.1);
|
||||
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(45, 55, 72, 0.07);
|
||||
--bs-box-shadow-lg: 0 1rem 3rem rgba(45, 55, 72, 0.15);
|
||||
}
|
||||
|
||||
/* Dark Mode (Bootstrap's preferred way) */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--bs-primary: #ff9cd7; /* Pastel Pink */
|
||||
--bs-secondary: #b39afd; /* Light Lavender */
|
||||
--bs-success: #8fffd9; /* Lighter Mint */
|
||||
--bs-info: #90e7ff; /* Pastel Sky Blue */
|
||||
--bs-warning: #fff4b1; /* Pale Yellow */
|
||||
--bs-danger: #ffb1b8; /* Soft Coral */
|
||||
--bs-light: #2a102d; /* Deep Purple-Black */
|
||||
--bs-dark: #fff7fa; /* Reverse for dark backgrounds */
|
||||
/*
|
||||
* =================================================================================================
|
||||
* 🌙✨ DARK MODE: VOGUE AFTER MIDNIGHT ✨🌙
|
||||
*
|
||||
* Because fabulousness doesn't sleep. This is for the night owls, the dreamers,
|
||||
* and everyone who knows the party really starts after dark.
|
||||
* =================================================================================================
|
||||
*/
|
||||
|
||||
--bs-body-bg: #2a102d;
|
||||
--bs-body-color: #fff7fa;
|
||||
--bs-link-color: #ff9cd7;
|
||||
--bs-link-hover-color: #b39afd;
|
||||
--bs-border-color: #6e3a6e;
|
||||
}
|
||||
}
|
||||
[data-bs-theme=dark] {
|
||||
color-scheme: dark;
|
||||
|
||||
/* 💅 Dark Mode Neutrals: Still Chic 💅 */
|
||||
--bs-body-color: var(--bs-gray-300);
|
||||
--bs-body-bg: var(--bs-gray-900);
|
||||
--bs-emphasis-color: var(--bs-white);
|
||||
--bs-secondary-color: rgba(237, 242, 247, 0.75);
|
||||
--bs-secondary-bg: var(--bs-gray-800);
|
||||
--bs-tertiary-color: rgba(237, 242, 247, 0.5);
|
||||
--bs-tertiary-bg: #222938; /* A slightly bluer dark gray */
|
||||
|
||||
/* 💖 Semantic Roles: Nightlife Edition 💖 */
|
||||
/* We use the same vibrant colors but adjust text emphasis and backgrounds for contrast */
|
||||
--bs-primary-text-emphasis: #A3A0FF;
|
||||
--bs-secondary-text-emphasis: #FFA8B9;
|
||||
--bs-success-text-emphasis: #79F3B3;
|
||||
--bs-info-text-emphasis: #99E5FF;
|
||||
--bs-warning-text-emphasis: #FFC98B;
|
||||
--bs-danger-text-emphasis: #FF7B96;
|
||||
--bs-light-text-emphasis: #F7FAFC;
|
||||
--bs-dark-text-emphasis: #E2E8F0;
|
||||
|
||||
--bs-primary-bg-subtle: #2A2859;
|
||||
--bs-secondary-bg-subtle: #592432;
|
||||
--bs-success-bg-subtle: #144A29;
|
||||
--bs-info-bg-subtle: #194A59;
|
||||
--bs-warning-bg-subtle: #593918;
|
||||
--bs-danger-bg-subtle: #591422;
|
||||
--bs-light-bg-subtle: var(--bs-gray-800);
|
||||
--bs-dark-bg-subtle: var(--bs-gray-900);
|
||||
|
||||
--bs-primary-border-subtle: #4D49A6;
|
||||
--bs-secondary-border-subtle: #A6435C;
|
||||
--bs-success-border-subtle: #248047;
|
||||
--bs-info-border-subtle: #2D8DA6;
|
||||
--bs-warning-border-subtle: #A66629;
|
||||
--bs-danger-border-subtle: #A6273D;
|
||||
--bs-light-border-subtle: var(--bs-gray-700);
|
||||
--bs-dark-border-subtle: var(--bs-gray-800);
|
||||
|
||||
/* 🎨 Core Styles for the Afterparty 🎨 */
|
||||
--bs-heading-color: inherit;
|
||||
--bs-link-color: var(--bs-blue);
|
||||
--bs-link-hover-color: var(--bs-cyan);
|
||||
--bs-code-color: var(--bs-secondary);
|
||||
--bs-highlight-bg: #403d07;
|
||||
--bs-border-color: var(--bs-gray-700);
|
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
/* Top Navigation Bar Styles */
|
||||
main {
|
||||
margin-top: 20px;
|
||||
|
|
6
public/assets/js/bootstrap.bundle.min.js
vendored
6
public/assets/js/bootstrap.bundle.min.js
vendored
File diff suppressed because one or more lines are too long
|
@ -6,7 +6,11 @@ namespace App\Controller;
|
|||
|
||||
use App\Entity\DrinkType;
|
||||
use App\Form\DrinkTypeForm;
|
||||
use App\Form\DrinkTypeFormCurrentStockForm;
|
||||
use App\Repository\DrinkTypeRepository;
|
||||
use App\Repository\PropertyChangeLogRepository;
|
||||
use App\Service\DrinkType\GetStockHistory;
|
||||
use App\Service\DrinkType\GetWantedHistory;
|
||||
use App\Service\InventoryService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
|
@ -18,10 +22,10 @@ use Symfony\Component\Routing\Attribute\Route;
|
|||
final class DrinkTypeController extends AbstractController
|
||||
{
|
||||
#[Route(name: 'app_drink_type_index', methods: ['GET'])]
|
||||
public function index(InventoryService $inventoryService): Response
|
||||
public function index(DrinkTypeRepository $drinkTypeRepository): Response
|
||||
{
|
||||
return $this->render('drink_type/index.html.twig', [
|
||||
'drink_stocks' => $inventoryService->getAllDrinkTypesWithStockLevels(true),
|
||||
'drink_types' => $drinkTypeRepository->findAll(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -46,28 +50,20 @@ final class DrinkTypeController extends AbstractController
|
|||
}
|
||||
|
||||
#[Route(path: '/{id}', name: 'app_drink_type_show', methods: ['GET'])]
|
||||
public function show(DrinkType $drinkType, PropertyChangeLogRepository $propertyChangeLogRepository): Response
|
||||
public function show(
|
||||
DrinkType $drinkType,
|
||||
GetStockHistory $getStockHistory,
|
||||
GetWantedHistory $getWantedHistory,
|
||||
): Response
|
||||
{
|
||||
// Get orders that contain this drink type
|
||||
$orderItems = $drinkType->getOrderItems();
|
||||
|
||||
// Get inventory history for this drink type
|
||||
$inventoryRecords = $drinkType->getInventoryRecords();
|
||||
|
||||
// Get desired stock history from PropertyChangeLog
|
||||
$desiredStockHistory = $propertyChangeLogRepository->findBy([
|
||||
'entityClass' => DrinkType::class,
|
||||
'propertyName' => 'desiredStock',
|
||||
'entityId' => $drinkType->getId(),
|
||||
], [
|
||||
'changeDate' => 'DESC',
|
||||
]);
|
||||
|
||||
return $this->render('drink_type/show.html.twig', [
|
||||
'drink_type' => $drinkType,
|
||||
'order_items' => $orderItems,
|
||||
'inventory_records' => $inventoryRecords,
|
||||
'desired_stock_history' => $desiredStockHistory,
|
||||
'stock_history' => $getStockHistory($drinkType),
|
||||
'wanted_history' => $getWantedHistory($drinkType),
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -89,6 +85,24 @@ final class DrinkTypeController extends AbstractController
|
|||
]);
|
||||
}
|
||||
|
||||
#[Route(path: '/{id}/update-stock', name: 'app_drink_type_update_stock', methods: ['GET', 'POST'])]
|
||||
public function updateStock(Request $request, DrinkType $drinkType, EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
$form = $this->createForm(DrinkTypeFormCurrentStockForm::class, $drinkType);
|
||||
$form->handleRequest($request);
|
||||
|
||||
if ($form->isSubmitted() && $form->isValid()) {
|
||||
$entityManager->flush();
|
||||
|
||||
return $this->redirectToRoute('app_index', [], Response::HTTP_SEE_OTHER);
|
||||
}
|
||||
|
||||
return $this->render('drink_type/edit.html.twig', [
|
||||
'drink_type' => $drinkType,
|
||||
'form' => $form,
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route(path: '/{id}', name: 'app_drink_type_delete', methods: ['POST'])]
|
||||
public function delete(Request $request, DrinkType $drinkType, EntityManagerInterface $entityManager): Response
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Repository\DrinkTypeRepository;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Routing\Attribute\Route;
|
||||
|
@ -11,8 +12,11 @@ use Symfony\Component\Routing\Attribute\Route;
|
|||
#[Route(path: '/', name: 'app_index')]
|
||||
final class Index extends AbstractController
|
||||
{
|
||||
public function __invoke(): Response
|
||||
public function __invoke(DrinkTypeRepository $drinkTypeRepository): Response
|
||||
{
|
||||
return new Response('<h1>Hello World!</h1>');
|
||||
return $this->render('index.html.twig', [
|
||||
'drinkTypes' => $drinkTypeRepository->findWanted(),
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,11 @@ class DrinkTypeForm extends AbstractType
|
|||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder->add('name')->add('description')->add('desiredStock', NumberType::class);
|
||||
$builder
|
||||
->add('name')
|
||||
->add('description')
|
||||
->add('currentStock', NumberType::class)
|
||||
->add('wantedStock', NumberType::class);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
|
|
|
@ -5,34 +5,23 @@ declare(strict_types=1);
|
|||
namespace App\Form;
|
||||
|
||||
use App\Entity\DrinkType;
|
||||
use App\Entity\InventoryRecord;
|
||||
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\NumberType;
|
||||
use Symfony\Component\Form\FormBuilderInterface;
|
||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||
|
||||
class InventoryRecordForm extends AbstractType
|
||||
class DrinkTypeFormCurrentStockForm extends AbstractType
|
||||
{
|
||||
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||
{
|
||||
$builder
|
||||
->add('quantity', NumberType::class)
|
||||
->add('drinkType', EntityType::class, [
|
||||
'class' => DrinkType::class,
|
||||
'choice_label' => 'id',
|
||||
'attr' => [
|
||||
'style' => 'display: none;',
|
||||
],
|
||||
'label' => false,
|
||||
])
|
||||
;
|
||||
->add('currentStock', NumberType::class);
|
||||
}
|
||||
|
||||
public function configureOptions(OptionsResolver $resolver): void
|
||||
{
|
||||
$resolver->setDefaults([
|
||||
'data_class' => InventoryRecord::class,
|
||||
'data_class' => DrinkType::class,
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -10,19 +10,18 @@
|
|||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Description</th>
|
||||
<th>DesiredStock</th>
|
||||
<th>DrinkStock</th>
|
||||
<th>Wanted Stock</th>
|
||||
<th>Current Stock</th>
|
||||
<th>actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for drink_stock in drink_stocks %}
|
||||
{% set drink_type = drink_stock.record.drinkType %}
|
||||
{% for drink_type in drink_types %}
|
||||
<tr>
|
||||
<td>{{ drink_type.name }}</td>
|
||||
<td>{{ drink_type.description }}</td>
|
||||
<td>{{ drink_type.desiredStock }}</td>
|
||||
<td>{{ drink_stock.record.quantity }}</td>
|
||||
<td>{{ drink_type.wantedStock }}</td>
|
||||
<td>{{ drink_type.currentStock }}</td>
|
||||
<td>
|
||||
<a href="{{ path('app_drink_type_show', {'id': drink_type.id}) }}">show</a>
|
||||
<a href="{{ path('app_drink_type_edit', {'id': drink_type.id}) }}">edit</a>
|
||||
|
|
|
@ -36,8 +36,12 @@
|
|||
<td>{{ drink_type.description }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>DesiredStock</th>
|
||||
<td>{{ drink_type.desiredStock }}</td>
|
||||
<th>Current Stock</th>
|
||||
<td>{{ drink_type.currentStock }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Wanted Stock</th>
|
||||
<td>{{ drink_type.wantedStock }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
@ -87,7 +91,7 @@
|
|||
<h5 class="card-title">Inventory History</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if inventory_records|length > 0 %}
|
||||
{% if stock_history|length > 0 %}
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -96,10 +100,10 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for record in inventory_records %}
|
||||
{% for record in stock_history %}
|
||||
<tr>
|
||||
<td>{{ record.createdAt|date('Y-m-d H:i:s') }}</td>
|
||||
<td>{{ record.quantity }}</td>
|
||||
<td>{{ record.changeDate|date('Y-m-d H:i:s') }}</td>
|
||||
<td>{{ record.newValue }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
@ -119,7 +123,7 @@
|
|||
<h5 class="card-title">Desired Stock History</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
{% if desired_stock_history|length > 0 %}
|
||||
{% if wanted_history|length > 0 %}
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -128,7 +132,7 @@
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for log in desired_stock_history %}
|
||||
{% for log in wanted_history %}
|
||||
<tr>
|
||||
<td>{{ log.changeDate|date('Y-m-d H:i:s') }}</td>
|
||||
<td>{{ log.newValue }}</td>
|
||||
|
|
|
@ -5,35 +5,6 @@
|
|||
{% block body %}
|
||||
<div class="container">
|
||||
<h1>Drink Inventory</h1>
|
||||
{% if low is not same as([]) %}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">Low Stock Alert</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Drink Name</th>
|
||||
<th>Current Stock</th>
|
||||
<th>Desired Stock</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for lowStock in low %}
|
||||
<tr>
|
||||
<td><a href="{{ path('app_drink_type_show', {'id': lowStock.record.drinkType.id}) }}">{{ lowStock.record.drinkType.name }}</a></td>
|
||||
<td>{{ lowStock.record.quantity }}</td>
|
||||
<td>{{ lowStock.record.drinkType.desiredStock }}</td>
|
||||
<td>{{ lowStock.stock.value|capitalize }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title">Drink Inventory Overview</h5>
|
||||
|
@ -43,36 +14,22 @@
|
|||
<thead>
|
||||
<tr>
|
||||
<th>Drink Name</th>
|
||||
<th>Description</th>
|
||||
<th>Current Stock</th>
|
||||
<th>Desired Stock</th>
|
||||
<th>Status</th>
|
||||
<th>Wanted Stock</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for drinkStock in drinkStocks %}
|
||||
{% set rowClass = '' %}
|
||||
{% if drinkStock.stock.value == 'critical' %}
|
||||
{% set rowClass = 'table-danger' %}
|
||||
{% elseif drinkStock.stock.value == 'low' %}
|
||||
{% set rowClass = 'table-warning' %}
|
||||
{% elseif drinkStock.stock.value == 'high' %}
|
||||
{% set rowClass = 'table-success' %}
|
||||
{% endif %}
|
||||
<tr class="{{ rowClass }}">
|
||||
<td><a href="{{ path('app_drink_type_show', {'id': drinkStock.record.drinkType.id}) }}">{{ drinkStock.record.drinkType.name }}</a></td>
|
||||
<td>{{ drinkStock.record.quantity }}</td>
|
||||
<td>{{ drinkStock.record.drinkType.desiredStock }}</td>
|
||||
<td>{{ drinkStock.stock.value|capitalize }}</td>
|
||||
{% for drinkType in drinkTypes %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{ path('app_drink_type_show', {'id': drinkType.id}) }}">{{ drinkType.name }}</a>
|
||||
</td>
|
||||
<td>{{ drinkType.description }}</td>
|
||||
<td>{{ drinkType.currentStock }}</td>
|
||||
<td>{{ drinkType.wantedStock }}</td>
|
||||
<td>
|
||||
<a href="{{ path('app_inventory_record_modal', {drinkType: drinkStock.record.drinkType.id}) }}"
|
||||
class="btn btn-primary"
|
||||
hx-get="{{ path('app_inventory_record_modal', {drinkType: drinkStock.record.drinkType.id}) }}"
|
||||
hx-target="#htmxModalBody"
|
||||
hx-trigger="click"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#htmxModal"
|
||||
data-drink-name="{{ drinkStock.record.drinkType.name }}">Update Stock</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
@ -81,7 +38,6 @@
|
|||
<div class="mt-3">
|
||||
<a href="{{ path('app_drink_type_index') }}" class="btn btn-primary">View All Drinks</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -14,5 +14,5 @@ test('Hello World', function (): void {
|
|||
|
||||
// Validate a successful response and some content
|
||||
$this->assertResponseIsSuccessful();
|
||||
$this->assertSelectorTextContains('h1', 'Hello World');
|
||||
$this->assertSelectorTextContains('h1', 'Drink Inventory');
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue