From 1907e69c5e7415563c0f9dc3cbf060a09ec997df Mon Sep 17 00:00:00 2001 From: KATO So Date: Wed, 13 Nov 2024 10:24:24 +0900 Subject: [PATCH 1/4] =?UTF-8?q?chore:=20=E3=82=B3=E3=83=B3=E3=83=86?= =?UTF-8?q?=E3=83=8A=E3=81=8C=E3=83=93=E3=83=AB=E3=83=89=E3=81=A7=E3=81=8D?= =?UTF-8?q?=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB=E4=BF=AE=E6=AD=A3=20(#34)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 32 ++++++++++++++++++++++++-------- compose.yaml | 2 +- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/Dockerfile b/Dockerfile index 0df215c..8a7a81f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,25 +18,40 @@ WORKDIR /app COPY --chown=appuser:appuser .tool-versions ./ RUN . ~/.bashrc && mise install -FROM base AS builder +FROM base AS prod-deps WORKDIR /app USER root RUN mkdir /app/node_modules && chown -R appuser:appuser /app USER appuser COPY --chown=appuser:appuser package.json bun.lockb ./ -RUN bun install --frozen-lockfile --verbose +COPY --chown=appuser:appuser prisma ./prisma +RUN bun install --frozen-lockfile --production && \ + bun prisma generate +USER root +RUN mkdir -p /tmp/prod-deps && \ + cp -r node_modules /tmp/prod-deps/ && \ + chown -R 65532:65532 /tmp/prod-deps + +FROM base AS deps +WORKDIR /app +USER root +RUN mkdir /app/node_modules && chown -R appuser:appuser /app +USER appuser +COPY --chown=appuser:appuser package.json bun.lockb ./ +RUN bun install --frozen-lockfile + +FROM deps AS builder +WORKDIR /app +USER appuser COPY --chown=appuser:appuser . . -RUN bun prisma generate ENV DATABASE_URL=file:/app/prisma/data/deploy.db RUN mkdir -p prisma/data && \ touch prisma/data/deploy.db && \ - bun prisma migrate deploy -RUN bun run build + bun prisma migrate deploy && \ + bun run build USER root -RUN bun install --frozen-lockfile --production && \ - mkdir -p /tmp/prod/app && \ +RUN mkdir -p /tmp/prod/app && \ cp -r build /tmp/prod/app/ && \ - cp -r node_modules /tmp/prod/app/ && \ cp -r prisma /tmp/prod/app/ && \ cp package.json /tmp/prod/app/ && \ chown -R 65532:65532 /tmp/prod && \ @@ -47,6 +62,7 @@ RUN bun install --frozen-lockfile --production && \ FROM gcr.io/distroless/nodejs22-debian12:nonroot AS runner WORKDIR /app +COPY --from=prod-deps /tmp/prod-deps/node_modules ./node_modules COPY --from=builder /tmp/prod/app ./ ENV NODE_ENV=production \ DATABASE_URL=file:/app/prisma/data/deploy.db diff --git a/compose.yaml b/compose.yaml index 3e3affa..0ae3966 100644 --- a/compose.yaml +++ b/compose.yaml @@ -1,7 +1,7 @@ name: order services: - deploy: + production: build: context: . dockerfile: Dockerfile From be37a683d5b2badaf1aff715cf6a5a9ae065280a Mon Sep 17 00:00:00 2001 From: BruCandy <161817534+BruCandy@users.noreply.github.com> Date: Sat, 16 Nov 2024 13:52:45 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=E6=B3=A8=E6=96=87=E5=B1=A5=E6=AD=B4?= =?UTF-8?q?=E3=83=9A=E3=83=BC=E3=82=B8=E3=81=AE=E3=82=A2=E3=83=83=E3=83=97?= =?UTF-8?q?=E3=83=87=E3=83=BC=E3=83=88=20(#35)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/routes/order_table.tsx | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/app/routes/order_table.tsx b/app/routes/order_table.tsx index 4d63dc1..08751df 100644 --- a/app/routes/order_table.tsx +++ b/app/routes/order_table.tsx @@ -39,8 +39,10 @@ export default function OrderTable() { ID + 注文日時 テーブル番号 注文内容 + 売上 ステータス @@ -61,10 +63,33 @@ export default function OrderTable() { const quantities = filteredDetails.map( (detail) => detail.quantity, ) + const totalPrice = filteredDetails.reduce( + (sum, detail) => + sum + + detail.quantity * + products + .filter( + (product) => detail.product_id === product.product_id, + ) + .reduce((sum, product) => sum + product.price, 0), + 0, + ) + const createTime = new Date(order.createTime).toLocaleString( + "ja-JP", + { + timeZone: "Asia/Tokyo", + year: "numeric", + month: "2-digit", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + }, + ) return ( {order.order_id} + {createTime} {order.table_number} {productNames.map((name, index) => ( @@ -73,6 +98,7 @@ export default function OrderTable() { ))} + {totalPrice}円 {order.status} ) From 455fcfee9546abb9aa0abf683602debe19299c59 Mon Sep 17 00:00:00 2001 From: BruCandy <161817534+BruCandy@users.noreply.github.com> Date: Sat, 16 Nov 2024 13:53:00 +0900 Subject: [PATCH 3/4] =?UTF-8?q?Products=E3=81=AB=E5=9C=A8=E5=BA=AB(stock)?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0=20(#36)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../organisms/reception/ReceptionCard.tsx | 29 +++++++++-- .../organisms/register/ProductCard.tsx | 4 +- app/crud/crud_products.ts | 18 +++++++ app/routes/reception.tsx | 48 +++++++++++++------ app/routes/register.tsx | 44 +++++++++++++++-- app/type/typeproduct.ts | 1 + .../20241108122708_add_stock/migration.sql | 21 ++++++++ prisma/schema.prisma | 1 + 8 files changed, 143 insertions(+), 23 deletions(-) create mode 100644 prisma/migrations/20241108122708_add_stock/migration.sql diff --git a/app/components/organisms/reception/ReceptionCard.tsx b/app/components/organisms/reception/ReceptionCard.tsx index 0ee3f76..0ee4e63 100644 --- a/app/components/organisms/reception/ReceptionCard.tsx +++ b/app/components/organisms/reception/ReceptionCard.tsx @@ -4,21 +4,42 @@ import { TypeProduct } from "~/type/typeproduct" import PropTypes from "prop-types" type Props = { + quantity?: number product: TypeProduct addOrder: (product: TypeProduct) => void cancelOrder: (product: TypeProduct) => void } export const ReceptionCard: FC = memo((props) => { - const { product, addOrder, cancelOrder } = props + const { quantity = 0, product, addOrder, cancelOrder } = props return ( - +

ID:{product.product_id}

{product.product_name} 価格:{product.price} - @@ -36,6 +37,7 @@ ProductCard.propTypes = { product_id: PropTypes.number.isRequired, product_name: PropTypes.string.isRequired, price: PropTypes.number.isRequired, + stock: PropTypes.number.isRequired, }).isRequired, clickDelete: PropTypes.func.isRequired, clickChange: PropTypes.func.isRequired, diff --git a/app/crud/crud_products.ts b/app/crud/crud_products.ts index 51e150b..7aa0791 100644 --- a/app/crud/crud_products.ts +++ b/app/crud/crud_products.ts @@ -7,11 +7,13 @@ const prisma = new PrismaClient() export async function createProduct(data: { product_name: string price: number + stock: number }) { return await prisma.products.create({ data: { product_name: data.product_name, price: data.price, + stock: data.stock, }, }) } @@ -26,6 +28,7 @@ export async function updateProduct( product_id: number, product_name: string, price: number, + stock: number, ) { return await prisma.products.update({ where: { @@ -34,10 +37,25 @@ export async function updateProduct( data: { product_name: product_name, price: price, + stock: stock, }, }) } +//在庫の変更 +export async function updateStock(data: { + product_id: number + stock: number | undefined + num: number +}) { + return await prisma.products.update({ + where: { + product_id: data.product_id, + }, + data: { stock: data.stock ? data.stock - data.num : 0 }, + }) +} + //同じ商品名の商品が既に存在するか確認する export async function existProduct(name: string) { return await prisma.products.findFirst({ diff --git a/app/routes/reception.tsx b/app/routes/reception.tsx index 3cc35c7..4519daa 100644 --- a/app/routes/reception.tsx +++ b/app/routes/reception.tsx @@ -23,7 +23,7 @@ import { useEffect, useState } from "react" import { ReceptionCard } from "~/components/organisms/reception/ReceptionCard" import { createOrderDetail } from "~/crud/crud_details" import { createOrder } from "~/crud/crud_orders" -import { readProduct } from "~/crud/crud_products" +import { readProduct, updateStock } from "~/crud/crud_products" import { useMessage } from "~/hooks/useMessage" // type TypeOrder = { @@ -73,9 +73,9 @@ export default function Reception() { useEffect(() => { if (actionData?.success === true) { + setOrder([]) setTotal(0) // setDecision(false) - setOrder([]) showMessage({ title: "注文しました", status: "success" }) onClose() setTableNumber("") @@ -88,6 +88,7 @@ export default function Reception() { product_id: number product_name: string price: number + stock: number }) => { setOrder((prevOrder) => { const existingProduct = prevOrder.find( @@ -171,15 +172,21 @@ export default function Reception() {
- {products.map((product) => ( - - - - ))} + {products.map((product) => { + const selectedOrder = order.find( + (order) => order.product_id === product.product_id, + ) + return ( + + + + ) + })}
@@ -264,13 +271,24 @@ export const action: ActionFunction = async ({ status: "accept", }) - for (let i = 0; i < product_ids.length; i++) { + const products = await readProduct() + + product_ids.map(async (product_id, index) => { + const quantity = quantities[index] + const product = products.find((p) => p.product_id === product_id) + await createOrderDetail({ order_id: order.order_id, - product_id: product_ids[i], - quantity: quantities[i], + product_id: product_id, + quantity: quantity, }) - } + + await updateStock({ + product_id: product_id, + stock: product?.stock, + num: quantity, + }) + }) return { success: true } } diff --git a/app/routes/register.tsx b/app/routes/register.tsx index 2d37ce0..bd08d07 100644 --- a/app/routes/register.tsx +++ b/app/routes/register.tsx @@ -10,7 +10,6 @@ import { ModalCloseButton, ModalContent, ModalFooter, - ModalHeader, ModalOverlay, Stack, useDisclosure, @@ -42,6 +41,7 @@ type ActionData = { export default function Register() { const [name, setName] = useState("") const [price, setPrice] = useState("") + const [stock, setStock] = useState("") const [isLoading, setLoading] = useState(false) const actionData = useActionData() const { showMessage } = useMessage() @@ -69,6 +69,7 @@ export default function Register() { if (actionData?.success && actionData?.method === "POST") { setName("") setPrice("") + setStock("") setLoading(false) showMessage({ title: "登録完了", status: "success" }) } @@ -105,6 +106,10 @@ export default function Register() { setPrice(e.target.value) } + const stockChange = (e: React.ChangeEvent) => { + setStock(e.target.value) + } + const productOpen = () => { setOpen(true) } @@ -145,6 +150,15 @@ export default function Register() { } } + const handleStockChange = (e: React.ChangeEvent) => { + if (changeProduct) { + setChangeProduct({ + ...changeProduct, + stock: Number(e.target.value), + }) + } + } + return (
@@ -352,6 +385,7 @@ export const action: ActionFunction = async ({ ) { const product_name = formData.get("product_name") const price = Number(formData.get("price")) + const stock = Number(formData.get("stock")) if (typeof product_name === "string") { const isExist = await existProduct(product_name) @@ -369,6 +403,7 @@ export const action: ActionFunction = async ({ await createProduct({ product_name, price, + stock, }) return json({ success: true, method: request.method }) @@ -405,9 +440,10 @@ export const action: ActionFunction = async ({ const product_id = Number(formData.get("product_id")) const product_name = formData.get("product_name") const price = Number(formData.get("price")) + const stock = Number(formData.get("stock")) if (typeof product_name === "string") { - await updateProduct(product_id, product_name, price) + await updateProduct(product_id, product_name, price, stock) return json({ success: true, method: method }) } else { return json({ success: false, error: "no product_name", method: method }) diff --git a/app/type/typeproduct.ts b/app/type/typeproduct.ts index 128d378..2acfa52 100644 --- a/app/type/typeproduct.ts +++ b/app/type/typeproduct.ts @@ -2,4 +2,5 @@ export type TypeProduct = { product_id: number product_name: string price: number + stock: number } diff --git a/prisma/migrations/20241108122708_add_stock/migration.sql b/prisma/migrations/20241108122708_add_stock/migration.sql new file mode 100644 index 0000000..1e19f48 --- /dev/null +++ b/prisma/migrations/20241108122708_add_stock/migration.sql @@ -0,0 +1,21 @@ +/* + Warnings: + + - Added the required column `stock` to the `Products` table without a default value. This is not possible if the table is not empty. + +*/ +-- RedefineTables +PRAGMA defer_foreign_keys=ON; +PRAGMA foreign_keys=OFF; +CREATE TABLE "new_Products" ( + "product_id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + "product_name" TEXT NOT NULL, + "price" INTEGER NOT NULL, + "stock" INTEGER NOT NULL +); +INSERT INTO "new_Products" ("price", "product_id", "product_name") SELECT "price", "product_id", "product_name" FROM "Products"; +DROP TABLE "Products"; +ALTER TABLE "new_Products" RENAME TO "Products"; +CREATE UNIQUE INDEX "Products_product_name_key" ON "Products"("product_name"); +PRAGMA foreign_keys=ON; +PRAGMA defer_foreign_keys=OFF; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index af25e61..2fe3545 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -34,5 +34,6 @@ model Products{ product_id Int @id @default(autoincrement()) product_name String @unique price Int + stock Int orderDetails Order_details[] } \ No newline at end of file From 1aa638d5e4d9d826b847ae230ab5c29a253cf23f Mon Sep 17 00:00:00 2001 From: BruCandy <161817534+BruCandy@users.noreply.github.com> Date: Sun, 17 Nov 2024 01:17:42 +0900 Subject: [PATCH 4/4] =?UTF-8?q?=E7=B0=A1=E6=98=93=E3=83=AC=E3=82=B8?= =?UTF-8?q?=E3=81=AE=E4=BD=9C=E6=88=90=20(#26)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../organisms/reception/Calculator.tsx | 45 ++++++++++++++ app/routes/reception.tsx | 61 ++++++++++--------- 2 files changed, 78 insertions(+), 28 deletions(-) create mode 100644 app/components/organisms/reception/Calculator.tsx diff --git a/app/components/organisms/reception/Calculator.tsx b/app/components/organisms/reception/Calculator.tsx new file mode 100644 index 0000000..b184cc4 --- /dev/null +++ b/app/components/organisms/reception/Calculator.tsx @@ -0,0 +1,45 @@ +import { Box, Button, HStack, Text, VStack } from "@chakra-ui/react" +import { FC, memo } from "react" + +export const Calculator: FC = memo(() => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +}) + +Calculator.displayName = "Calculator" diff --git a/app/routes/reception.tsx b/app/routes/reception.tsx index 4519daa..5a715b3 100644 --- a/app/routes/reception.tsx +++ b/app/routes/reception.tsx @@ -14,12 +14,14 @@ import { Stack, Text, useDisclosure, + VStack, Wrap, WrapItem, } from "@chakra-ui/react" import { ActionFunction, ActionFunctionArgs, json } from "@remix-run/node" import { Form, useActionData, useLoaderData } from "@remix-run/react" import { useEffect, useState } from "react" +import { Calculator } from "~/components/organisms/reception/Calculator" import { ReceptionCard } from "~/components/organisms/reception/ReceptionCard" import { createOrderDetail } from "~/crud/crud_details" import { createOrder } from "~/crud/crud_orders" @@ -195,34 +197,37 @@ export default function Reception() { - - - - 注文内容 - - - {order.map((item) => ( - - - 商品名:{item.product_name} 商品ID:{item.product_id} - - 数量:{item.quantity} - - ))} - - -------------------------------------------- - 合計:{total}円 - - テーブル番号: - - - - + + + + + 注文内容 + + + {order.map((item) => ( + + + 商品名:{item.product_name} 商品ID:{item.product_id} + + 数量:{item.quantity} + + ))} + + -------------------------------------------- + 合計:{total}円 + + テーブル番号: + + + + + +