DB של הזמנות
-
שלום לכולם
אני מנסה לבנות אתר להזמנות מוצרים
בניתי טבלא של מוקדי מכירה וטבלה של מוצרים וטבלה של הזמנות
עכשיו, היות שבהזמנה אחת יכול להיות כמה מוצרים, אז עשיתי טבלת בת של ההזמנות ששם לוקח ID הזמנה וID מוצר ומוסיף אותם
ונתקעתי בשלב הבא
שאני רוצה גם שהספקים יקבלו את ההזמנה אליהם
אז יצרתי טבלת הזמנות לספקים
אבל אני לא מצליח למצוא רעיון איך אני מחבר את ההזמנות של המוקדים להזמנות של הספקיםאני כותב כאן חלק מהמודלים בשביל הדוגמא
סנטר const sequelize = require("../../config/db.js"); const { DataTypes } = require("sequelize"); const CentersType = require("./centersType-model.js"); const Center = sequelize.define( "Centers", { name: { type: DataTypes.STRING, allowNull: false, }, city: { type: DataTypes.STRING, allowNull: false, }, address: { type: DataTypes.STRING, allowNull: false, }, // שעות פתיחה openingHours: { type: DataTypes.STRING, allowNull: false, }, phone: { type: DataTypes.STRING, allowNull: false, }, // סוג typeID: { type: DataTypes.INTEGER, allowNull: false, }, //חובות debts: { type: DataTypes.DECIMAL(10, 2), defaultValue: 0, }, status: { type: DataTypes.ENUM("active", "inactive"), defaultValue: "active", }, createdAt: { type: DataTypes.DATE, }, updatedAt: { type: DataTypes.DATE, }, }, { charset: "utf8", collate: "utf8_unicode_ci", } ); Center.belongsTo(CentersType, { foreignKey: "typeID" }); module.exports = Center; // הוספת שורה על ידי שליחת פוסט עם הגייסון הבא: // { "name": "מרכז חדש", "city": "עיר", "address": "כתובת", "openingHours": "שעות פתיחה", "phone": "טלפון", "typeID": 1 } הספקים const sequelize = require("../../config/db.js"); const { DataTypes } = require("sequelize"); const Users = require("./users-model.js"); const Companies = sequelize.define( "Companies", { name: { type: DataTypes.STRING, allowNull: false, }, userId: { type: DataTypes.INTEGER, allowNull: false, }, address: { type: DataTypes.STRING, }, debts: { type: DataTypes.DECIMAL(10, 2), defaultValue: 0, }, status: { type: DataTypes.ENUM("active", "inactive"), defaultValue: "active", }, createdAt: { type: DataTypes.DATE, }, updatedAt: { type: DataTypes.DATE, }, }, { charset: "utf8", collate: "utf8_unicode_ci", } ); Companies.belongsTo(Users, { foreignKey: "userId" }); module.exports = Companies; // הוספת שורה על ידי שליחת פוסט עם הגייסון הבא: // { "name": "company name", "userId": 1, "address": "company address", "debts": 0, "status": "active" } המוצרים const sequelize = require("../../config/db.js"); const { DataTypes } = require("sequelize"); const Companies = require("./companies-model.js"); const ProductsType = require("./productsType-model.js"); const Products = sequelize.define( "Products", { name: { type: DataTypes.STRING, allowNull: false, }, // חברה companyId: { type: DataTypes.INTEGER, allowNull: false, }, // סוג typeId: { type: DataTypes.STRING, }, // כמות באריזה quantityInPackage: { type: DataTypes.INTEGER, }, // המחיר שאני קונה בו priceCompoanies: { type: DataTypes.DECIMAL(10, 2), allowNull: false, }, status: { type: DataTypes.ENUM("active", "inactive"), defaultValue: "active", }, createdAt: { type: DataTypes.DATE, }, updatedAt: { type: DataTypes.DATE, }, }, { charset: "utf8", collate: "utf8_unicode_ci", } ); Products.belongsTo(Companies, { foreignKey: "companyId" }); Products.belongsTo( ProductsType, { foreignKey: "typeId" }); module.exports = Products; // הוספת שורה על ידי שליחת פוסט עם הגייסון הבא: // { "name": "מוצר חדש", "companyId": 1, "type": "סוג חדש", "priceCompoanies": 100 } מחירי המוצרים const sequelize = require("../../config/db.js"); const { DataTypes } = require("sequelize"); const Products = require("./products-model.js"); const CentersType = require("./centersType-model.js"); const Prices = sequelize.define("Prices", { productId: { type: DataTypes.INTEGER, allowNull: false, }, centersTypeId: { type: DataTypes.INTEGER, allowNull: false, }, price: { type: DataTypes.DECIMAL(10, 2), allowNull: false, }, priceDifference: { type: DataTypes.DECIMAL(10, 2), }, status: { type: DataTypes.ENUM("active", "inactive"), defaultValue: "active", }, createdAt: { type: DataTypes.DATE, }, updatedAt: { type: DataTypes.DATE, }, }); Prices.belongsTo(Products, { foreignKey: "productId" }); Prices.belongsTo(CentersType, { foreignKey: "centersTypeId" }); module.exports = Prices; // הוספת שורה על ידי שליחת פוסט עם הגייסון הבא: // { "productId": 1, "centerId": 1, "price": 100, "priceDifference": 10} טבלא הראשית של ההזמנות const sequelize = require("../../config/db.js"); const { DataTypes } = require("sequelize"); const Centers = require("./centers-model"); const Orders = sequelize.define("Orders", { // תאריך המכירה saleDate: { type: DataTypes.DATE, allowNull: false, }, // קוד מרכז centerId: { type: DataTypes.INTEGER, allowNull: false, }, // מחיר הזמנה totalPrice: { type: DataTypes.DECIMAL, allowNull: false, }, // רווח הזמנה totalProfit: { type: DataTypes.DECIMAL, allowNull: false, }, // הוצאות הזמנה totalExpenses: { type: DataTypes.DECIMAL, allowNull: false, }, // אישור הזמנה approved: { type: DataTypes.BOOLEAN, defaultValue: false, }, // תאריך יצירה createdAt: { type: DataTypes.DATE, }, // תאריך עדכון updatedAt: { type: DataTypes.DATE, }, }); Orders.belongsTo(Centers, { foreignKey: "centerId" }); module.exports = Orders; // הוספת שורה על ידי שליחת פוסט עם הגייסון הבא: // { "saleDate": "2021-09-01", "centerId": 1, "totalPrice": 1000, "approved": true, "status": "active" } טבלת בת של ההזמנות const sequelize = require("../../config/db.js"); const { DataTypes } = require("sequelize"); const Orders = require("./orders-model"); const Products = require("./products-model"); const OrderItems = sequelize.define("order_items", { // קוד הזמנה orderId: { type: DataTypes.INTEGER, allowNull: false, }, // קוד מוצר productId: { type: DataTypes.INTEGER, allowNull: false, }, // כמות quantity: { type: DataTypes.INTEGER, allowNull: false, }, // כמות * מחיר totalPrice: { type: DataTypes.DECIMAL(10, 2), allowNull: false, }, // כמות * הפרש מחיר totalDifference: { type: DataTypes.DECIMAL(10, 2), }, // תאריך יצירה createdAt: { type: DataTypes.DATE, }, // תאריך עדכון updatedAt: { type: DataTypes.DATE, }, }); OrderItems.belongsTo(Orders, { foreignKey: "orderId" }); OrderItems.belongsTo(Products, { foreignKey: "productId" }); module.exports = OrderItems; // הוספת שורה על ידי שליחת פוסט עם הגייסון הבא: // { "orderId": 1, "productId": 1, "quantity": 10, "price": 100, "total": 1000 } הטבלא של הזמנות לספקים - שאותה אני לא יודע איך לחבר const sequelize = require("../../config/db.js"); const { DataTypes } = require("sequelize"); const Companies = require("./companies-model.js"); const CompanyOrders = sequelize.define( "CompanyOrders", { // תאריך הזמנה orderDate: { type: DataTypes.DATE, allowNull: false, }, // קוד חברה companyId: { type: DataTypes.INTEGER, allowNull: false, }, // סכום הזמנה totalPrice: { type: DataTypes.DECIMAL, allowNull: false, }, // תאריך יצירה createdAt: { type: DataTypes.DATE, }, // תאריך עדכון updatedAt: { type: DataTypes.DATE, }, }, { charset: "utf8", collate: "utf8_unicode_ci", } ); CompanyOrders.belongsTo(Companies, { foreignKey: "companyId" }); module.exports = CompanyOrders;
-
לא ברור לי כ"כ הסיטואציה
כל מוקד מזמין בנפרד?
למה ההזמנה היא לא פר ספק? -
טבלאות:
ספקים
מוקדים
לקוחות
מוצרים (מכיל מזהה ספק)
הזמנות (מכיל גם מזהה לקוח, ומזהה מוקד)
פרטי הזמנה (מזהה הזמנה, מזהה מוצר)לשליפת כל המוצרים פר ספק פר מוקד,
אתה מחבר את ההזמנות עם הפרטי הזמנה, ומסנן/מקבץ לפי ספק ולפי מוקד.
בשביל לעשות כזה JOIN בsequelize תוכל לכתוב קודם SQL ואז לשאול פה (או בGPT?) איך כותבים זאת בsequelize. -
@meir-lamdan
את ההזמנה אני מקבל מהלקוח
היא מורכבת מכמה ספקים
ואני רוצה שכל ספק יקבל הזמנה אחת
שהיא מורכבת מכמה לקוחות -
@dovid כתב בDB של הזמנות:
טבלאות:
ספקים
מוקדים
לקוחות
מוצרים (מכיל מזהה ספק)
הזמנות (מכיל גם מזהה לקוח, ומזהה מוקד)
פרטי הזמנה (מזהה הזמנה, מזהה מוצר)לשליפת כל המוצרים פר ספק פר מוקד,
אתה מחבר את ההזמנות עם הפרטי הזמנה, ומסנן/מקבץ לפי ספק ולפי מוקד.
בשביל לעשות כזה JOIN בsequelize תוכל לכתוב קודם SQL ואז לשאול פה (או בGPT?) איך כותבים זאת בsequelize.לפי איך שזה נראה מדבריך החיבור בין הטבלאות הוא לא אמיתי אלא רק חזותי לפי שאילתא
וזה דופק לי את החלק של המחירים והחובות של כל מוקד
שאני רוצה שכל הזמנה יש את המחיר שלה וזה מתווסף לרשימת החובות של התחנה
וגם מאפשר לי לעשות שינויים לאחר זמן וכל המחירים שמורים בדאטה
אני צודק? -
@dovid אם אני יעשה הכל כשאילתות JOIN והמחיר יווצר בעזרת פונקציה, האם זה תקני
כלומר שבדאטה בעצם לא ישמר כלום
זה לא בעייתי?
שבמקרה של נפילת שרת אני מפסיד את כל הנתונים
לא עדיף שההזמנות והמחירים ישמרו בדאטה בצורה מסודרת שלא תוכל לגרום לשגיאות? -
@איש-פשוט-מאוד לפי התיאוריה האידאלית, אסור שבDATA זה יהיה כתוב בשום מקום, כי זה כפל נתונים (זה בבסיס חוקי הנרמול), כלומר כל שדה שניתן לחישוב אסור לשמירה. לכן הדרך שהצעתי היא בד"כ הדרך הטובה.
לעיתים כן בוחרים לשמור בטבלה נפרדת כזה ערך, או בגלל שיקולי ביצועים (למשל את יתרת החשבון בעו"ש יש מצב שלא רוצים לחשב כל פעם מיום פתיחת החשבון), או בגלל שיקולים שרירותיים של חילוט מצב, ששורת החוב תתנתק מכאן ואילך מהגורמים שחישבו אותה (שזה בדרך כלל זו החלטה שקשורה להתנהלות לא תקינה).
יש לציין שלהחלטה לשמור מידע כפול יש בעיות משמעותיות, זו לא סתם עבירה על המלצת ספרי הלימוד...לא הבנתי מה התכוונת במקרה שכתבת על נפילת שרת, המקרה הזה הוא דוקא עומד לטובת הימנעות משמירה כפולה, כי אם אתה שומר רק בטבלת הזמנות את המחיר אתה בפחות סיכון לאיבוד נתונים מאשר אם אתה מעתיק את הסכום למוקד לטבלה נפרדת, שאז יכול להיות כישלון חלקי ובעיית עקביות. טכנית יש לזה פתרונות, אבל ודאי שזה לא טיעון לטובת השמירה הכפולה.
-
@dovid כתב בDB של הזמנות:
לעיתים כן בוחרים לשמור בטבלה נפרדת כזה ערך, או בגלל שיקולי ביצועים (למשל את יתרת החשבון בעו"ש יש מצב שלא רוצים לחשב כל פעם מיום פתיחת החשבון
כתוספת:
כפי שראיתי בעבר במסדי נתונים של אי אלו תוכנות
הם שומרים גם את הסה"כ של המסמך בטבלת המסמך (בנידון דידן: עמודה עם ערך סה"כ הזמנה, בטבלת ההזמנות)
כך זה מאפשר להריץ דוחות על נתונים ללא צורך בתתי שאילתות
[ומאפשר לבדוק האם מישהו נגע בנתונים בטבלה המקושרת....] -
@dovid כתב בDB של הזמנות:
@איש-פשוט-מאוד לפי התיאוריה האידאלית, אסור שבDATA זה יהיה כתוב בשום מקום, כי זה כפל נתונים (זה בבסיס חוקי הנרמול), כלומר כל שדה שניתן לחישוב אסור לשמירה. לכן הדרך שהצעתי היא בד"כ הדרך הטובה.
זה אני יודע
מכאן נובע כל הקושי שלי
אחרת הייתי עושה פשוט טבלה שלימה נפרדת של הזמנות לספקים ולתחנות, ושולח פוסט בבת אחת לשתיהם@dovid כתב בDB של הזמנות:
לא הבנתי מה התכוונת במקרה שכתבת על נפילת שרת, המקרה הזה הוא דוקא עומד לטובת הימנעות משמירה כפולה, כי אם אתה שומר רק בטבלת הזמנות את המחיר אתה בפחות סיכון לאיבוד נתונים מאשר אם אתה מעתיק את הסכום למוקד לטבלה נפרדת, שאז יכול להיות כישלון חלקי ובעיית עקביות. טכנית יש לזה פתרונות, אבל ודאי שזה לא טיעון לטובת השמירה הכפולה.
עכשיו נפל לי האסימון למה אתה מתכוין
אני צריך טיפה לעבד בראש את הרעיון, אבל כבר יש לי כיוון
תודה רבה! -
@איש-פשוט-מאוד
@dovid
יש נקודה נוספת לדיון
וזה ערך המע"מ (לנוהגים.. כמובן...)במערכות תקניות נהוג לנהל את מחיר הפריט לפני מעמ
ויש לעיין האם לשמור את הנתון של ערך המעמ הנוכחי בטבלת הזמנות
מצד אחד זה נתון קבוע של תא בודד לפי טווח תאריכים
ולכן יש הגיון לשמור אותו פעם אחת בלבדמצד שני נוחות/קלות השליפה
במידה וזה מופיע כערך בשורת ההזמנה -
שמע"מ שומרים בטבלת הקבלות, שמה חייבים לחלט את הסכום וגם בגלל שזה טבלה אסורה לעדכון.
גם שמה אני רואה שנהוג לכתוב גם את הסכום לפני ואחרי וגם את ערך המעמ למרות שזה ניתן לחישוב כנראה לנוחות כאשר אמרת.
אני חושב שבטבלת הזמנות אפשר לחשב לפי ערכו של המע"מ (כקבוע או כערך משתנה).
אני לא הייתי שומר היסטורית את המע"מ כי אין לזה השלכה כל כך ברטרו, ומי שחוייב זה מופיע לו בקבלה.