Antaram commited on
Commit
6c1dc71
Β·
verified Β·
1 Parent(s): 797a029

Upload 13 files

Browse files
Files changed (4) hide show
  1. src/db/ca.pem +26 -0
  2. src/routes/lots.js +40 -0
  3. src/routes/transactions.js +85 -26
  4. src/server.js +73 -73
src/db/ca.pem ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEUDCCArigAwIBAgIUfwNzc0s5wNLad9xuTq9aKHnTIckwDQYJKoZIhvcNAQEM
3
+ BQAwQDE+MDwGA1UEAww1ODg2NWZlZTEtOTIyMy00MTMxLWIwNjItYWJlNDg5YWMw
4
+ ZTFmIEdFTiAxIFByb2plY3QgQ0EwHhcNMjUxMTI2MTMwMjIzWhcNMzUxMTI0MTMw
5
+ MjIzWjBAMT4wPAYDVQQDDDU4ODY1ZmVlMS05MjIzLTQxMzEtYjA2Mi1hYmU0ODlh
6
+ YzBlMWYgR0VOIDEgUHJvamVjdCBDQTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCC
7
+ AYoCggGBALXpJK142iOT6sCj2zc820av/G8Yr69U9oowbRuMBH+fot0Brz3IxxZz
8
+ 4Eb+g3OGfbytvz2A39W4Gf7vM1qzYTpvQeb3I1WEp6ECJIxixPpeAwVr5FYCMPgw
9
+ Tp3hg6BOnMUFHmS10942WzHWpx8JajZFLYeFtk1VgR7cxqMZ1UEKZlc6SrA8HBqM
10
+ ok3E0VvgA1jw0iiJtPG7NTEI5G5HOJ10sFttpf1KdhqWiwVqG1tRpRTwQpVDKvU4
11
+ JEvBCAonZ2gxp2rf/11KOOEgS3Rk9KzCHNYJ4zcg+9ipcpwyaD5hNWQKxO0XLoIj
12
+ bJaXPcevfHXebad1dVD+3+sJYaTLNRaIuRs6AYm7/c0OxaetLplyzyafsw0mZAp/
13
+ ZswnS8XvOUuqKJke2QR3zpJSOZQ9qbHygziDgg3erLO0s/EimVj/j6QPZoUjKXkJ
14
+ 8dWoiF7kkF+USynIEEKN87VRHbi+lepuC32TgXdPGyuN2cmrg1mtS9Y/jDqUlfl8
15
+ ElmfFTRbPwIDAQABo0IwQDAdBgNVHQ4EFgQUWWJ7i7Zro8zA4tEwfzNQpF9+IP4w
16
+ EgYDVR0TAQH/BAgwBgEB/wIBADALBgNVHQ8EBAMCAQYwDQYJKoZIhvcNAQEMBQAD
17
+ ggGBAFYTDm036bi/0vOtLEP9jqDc51SMF1rWKf7Gy/wKsUTO9j7egEayy/lpvhKd
18
+ DY8ioyeBHtREMZ7RmOah165OnzQa6/gvfXQG78MSyo16HIBK/VrICK1gGVNPp/u5
19
+ wWx6wZ1fN709xKO7Q+nbYoCbxmlY+3BJq5xfvxcN7YFtTtEV5MSVUB76r7Mb+flk
20
+ fq+0HjTpUEV/VmEncKrQaN345L0v/b6gxUjiQjHdi9McDybM1x2JV0dqea3ZXySU
21
+ Igx168r1IQuiKTHvHTzibAEllulYj598YBtMeXaBnOEZm3JUkPBuyFpW2j/CyJQ9
22
+ 9y0UfOZkLqwDA3G5xatR6TAcGH7eByDrVqEKWXg1fgIJ7fmMijWyzXelLiOX0agl
23
+ pa43TlAP5KZfeR3GOtFfNAhiW448LhpZvKGi2q75G71uTopKtK2EdOuzjYJZCXxA
24
+ YU0EkC3KrKl/jzVOgvHz8kc+HWj5khW/pm6knWstpb3AUg7nD151ejVQuIuI8oJJ
25
+ rwCc8g==
26
+ -----END CERTIFICATE-----
src/routes/lots.js CHANGED
@@ -75,4 +75,44 @@ router.get('/mirchi/:mirchiTypeId', async (req, res) => {
75
  }
76
  });
77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
  module.exports = router;
 
75
  }
76
  });
77
 
78
+ // POST check if lot number is unique
79
+ router.post('/check-unique', async (req, res) => {
80
+ try {
81
+ const { lot_number } = req.body;
82
+
83
+ if (!lot_number) {
84
+ return res.status(400).json({ success: false, message: 'Lot number is required' });
85
+ }
86
+
87
+ const result = await pool.query(
88
+ 'SELECT id FROM lots WHERE lot_number = $1',
89
+ [lot_number]
90
+ );
91
+
92
+ res.json({ exists: result.rows.length > 0 });
93
+ } catch (error) {
94
+ console.error('Error checking lot uniqueness:', error);
95
+ res.status(500).json({ success: false, message: error.message });
96
+ }
97
+ });
98
+
99
+ // GET available lots for a mirchi type (with remaining quantity > 0)
100
+ router.get('/available/:mirchiTypeId', async (req, res) => {
101
+ try {
102
+ const { mirchiTypeId } = req.params;
103
+ const result = await pool.query(
104
+ `SELECT * FROM lots
105
+ WHERE mirchi_type_id = $1
106
+ AND status = 'active'
107
+ AND remaining_quantity > 0
108
+ ORDER BY purchase_date DESC`,
109
+ [mirchiTypeId]
110
+ );
111
+ res.json(result.rows);
112
+ } catch (error) {
113
+ console.error('Error fetching available lots:', error);
114
+ res.status(500).json({ success: false, message: error.message });
115
+ }
116
+ });
117
+
118
  module.exports = router;
src/routes/transactions.js CHANGED
@@ -16,6 +16,7 @@ router.get('/', async (req, res) => {
16
  'mirchi_name', ti.mirchi_name,
17
  'quality', ti.quality,
18
  'lot_id', ti.lot_id,
 
19
  'poti_weights', ti.poti_weights,
20
  'gross_weight', ti.gross_weight,
21
  'poti_count', ti.poti_count,
@@ -44,6 +45,7 @@ router.get('/', async (req, res) => {
44
  )) FILTER (WHERE p.id IS NOT NULL) as payments
45
  FROM transactions t
46
  LEFT JOIN transaction_items ti ON t.id = ti.transaction_id
 
47
  LEFT JOIN expenses e ON t.id = e.transaction_id
48
  LEFT JOIN payments p ON t.id = p.transaction_id
49
  `;
@@ -97,6 +99,7 @@ router.get('/:id', async (req, res) => {
97
  'mirchi_name', ti.mirchi_name,
98
  'quality', ti.quality,
99
  'lot_id', ti.lot_id,
 
100
  'poti_weights', ti.poti_weights,
101
  'gross_weight', ti.gross_weight,
102
  'poti_count', ti.poti_count,
@@ -125,6 +128,7 @@ router.get('/:id', async (req, res) => {
125
  )) FILTER (WHERE p.id IS NOT NULL) as payments
126
  FROM transactions t
127
  LEFT JOIN transaction_items ti ON t.id = ti.transaction_id
 
128
  LEFT JOIN expenses e ON t.id = e.transaction_id
129
  LEFT JOIN payments p ON t.id = p.transaction_id
130
  WHERE t.id = $1
@@ -283,47 +287,100 @@ router.post('/', async (req, res) => {
283
  }
284
 
285
  // 6. Update lots (stock management)
286
- if (bill_type === 'jawaak' && !is_return) {
287
- // Purchase: Create new lots
 
288
  for (let i = 0; i < items.length; i++) {
289
  const item = items[i];
290
  const mirchi = await client.query('SELECT name FROM mirchi_types WHERE id = $1', [item.mirchi_type_id]);
291
  const mirchiName = mirchi.rows[0]?.name || 'Unknown';
292
 
293
- const lotId = uuidv4();
294
- const lotNumber = `LOT-${mirchiName.substring(0, 3).toUpperCase()}-${bill_date.replace(/-/g, '')}-${Date.now()}`;
 
 
 
 
 
295
 
296
- await client.query(
297
- `INSERT INTO lots (id, lot_number, mirchi_type_id, mirchi_name, total_quantity, remaining_quantity, purchase_date, status, avg_rate)
298
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
299
- [lotId, lotNumber, item.mirchi_type_id, mirchiName, item.net_weight, item.net_weight, bill_date, 'active', item.rate_per_kg]
300
- );
301
- }
302
- } else if (bill_type === 'awaak') {
303
- // Sales: Update lot quantities
304
- for (const item of items) {
305
- if (item.lot_id) {
306
- if (is_return) {
307
- // Sales return: Add stock back
308
  await client.query(
309
  `UPDATE lots
310
- SET remaining_quantity = remaining_quantity + $1,
311
- status = CASE WHEN remaining_quantity + $1 > 0 THEN 'active' ELSE status END
312
- WHERE id = $2`,
313
- [item.net_weight, item.lot_id]
 
 
 
 
 
 
 
 
314
  );
315
  } else {
316
- // Regular sale: Reduce stock
 
317
  await client.query(
318
- `UPDATE lots
319
- SET remaining_quantity = remaining_quantity - $1,
320
- status = CASE WHEN remaining_quantity - $1 <= 0 THEN 'sold_out' ELSE 'active' END
321
- WHERE id = $2`,
322
- [item.net_weight, item.lot_id]
 
 
 
 
323
  );
324
  }
325
  }
326
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
327
  }
328
 
329
  await client.query('COMMIT');
@@ -337,6 +394,7 @@ router.post('/', async (req, res) => {
337
  'mirchi_name', ti.mirchi_name,
338
  'quality', ti.quality,
339
  'lot_id', ti.lot_id,
 
340
  'poti_weights', ti.poti_weights,
341
  'gross_weight', ti.gross_weight,
342
  'poti_count', ti.poti_count,
@@ -365,6 +423,7 @@ router.post('/', async (req, res) => {
365
  )) FILTER (WHERE p.id IS NOT NULL) as payments
366
  FROM transactions t
367
  LEFT JOIN transaction_items ti ON t.id = ti.transaction_id
 
368
  LEFT JOIN expenses e ON t.id = e.transaction_id
369
  LEFT JOIN payments p ON t.id = p.transaction_id
370
  WHERE t.id = $1
 
16
  'mirchi_name', ti.mirchi_name,
17
  'quality', ti.quality,
18
  'lot_id', ti.lot_id,
19
+ 'lot_number', l.lot_number,
20
  'poti_weights', ti.poti_weights,
21
  'gross_weight', ti.gross_weight,
22
  'poti_count', ti.poti_count,
 
45
  )) FILTER (WHERE p.id IS NOT NULL) as payments
46
  FROM transactions t
47
  LEFT JOIN transaction_items ti ON t.id = ti.transaction_id
48
+ LEFT JOIN lots l ON ti.lot_id = l.id
49
  LEFT JOIN expenses e ON t.id = e.transaction_id
50
  LEFT JOIN payments p ON t.id = p.transaction_id
51
  `;
 
99
  'mirchi_name', ti.mirchi_name,
100
  'quality', ti.quality,
101
  'lot_id', ti.lot_id,
102
+ 'lot_number', l.lot_number,
103
  'poti_weights', ti.poti_weights,
104
  'gross_weight', ti.gross_weight,
105
  'poti_count', ti.poti_count,
 
128
  )) FILTER (WHERE p.id IS NOT NULL) as payments
129
  FROM transactions t
130
  LEFT JOIN transaction_items ti ON t.id = ti.transaction_id
131
+ LEFT JOIN lots l ON ti.lot_id = l.id
132
  LEFT JOIN expenses e ON t.id = e.transaction_id
133
  LEFT JOIN payments p ON t.id = p.transaction_id
134
  WHERE t.id = $1
 
287
  }
288
 
289
  // 6. Update lots (stock management)
290
+ // AWAAK = Purchase (Stock IN), JAWAAK = Sale (Stock OUT)
291
+ if (bill_type === 'awaak' && !is_return) {
292
+ // Purchase: Create new lots or update existing ones
293
  for (let i = 0; i < items.length; i++) {
294
  const item = items[i];
295
  const mirchi = await client.query('SELECT name FROM mirchi_types WHERE id = $1', [item.mirchi_type_id]);
296
  const mirchiName = mirchi.rows[0]?.name || 'Unknown';
297
 
298
+ // Check if lot_number is provided (user-entered or selected existing)
299
+ if (item.lot_number) {
300
+ // Check if lot already exists
301
+ const existingLot = await client.query(
302
+ 'SELECT id FROM lots WHERE lot_number = $1',
303
+ [item.lot_number]
304
+ );
305
 
306
+ if (existingLot.rows.length > 0) {
307
+ // Update existing lot - add stock
308
+ const lotId = existingLot.rows[0].id;
 
 
 
 
 
 
 
 
 
309
  await client.query(
310
  `UPDATE lots
311
+ SET total_quantity = total_quantity + $1,
312
+ remaining_quantity = remaining_quantity + $1,
313
+ status = 'active',
314
+ updated_at = CURRENT_TIMESTAMP
315
+ WHERE id = $2`,
316
+ [item.net_weight, lotId]
317
+ );
318
+
319
+ // Update item with lot_id
320
+ await client.query(
321
+ 'UPDATE transaction_items SET lot_id = $1 WHERE id = $2',
322
+ [lotId, item.id || uuidv4()]
323
  );
324
  } else {
325
+ // Create new lot with user-provided lot_number
326
+ const lotId = uuidv4();
327
  await client.query(
328
+ `INSERT INTO lots (id, lot_number, mirchi_type_id, mirchi_name, total_quantity, remaining_quantity, purchase_date, status, avg_rate)
329
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
330
+ [lotId, item.lot_number, item.mirchi_type_id, mirchiName, item.net_weight, item.net_weight, bill_date, 'active', item.rate_per_kg]
331
+ );
332
+
333
+ // Update item with lot_id
334
+ await client.query(
335
+ 'UPDATE transaction_items SET lot_id = $1 WHERE id = $2',
336
+ [lotId, item.id || uuidv4()]
337
  );
338
  }
339
  }
340
  }
341
+ } else if (bill_type === 'awaak' && is_return) {
342
+ // Purchase Return: Reduce stock from lots
343
+ for (const item of items) {
344
+ if (item.lot_id) {
345
+ await client.query(
346
+ `UPDATE lots
347
+ SET total_quantity = total_quantity - $1,
348
+ remaining_quantity = remaining_quantity - $1,
349
+ status = CASE WHEN remaining_quantity - $1 <= 0 THEN 'sold_out' ELSE 'active' END,
350
+ updated_at = CURRENT_TIMESTAMP
351
+ WHERE id = $2`,
352
+ [item.net_weight, item.lot_id]
353
+ );
354
+ }
355
+ }
356
+ } else if (bill_type === 'jawaak' && !is_return) {
357
+ // Sale: Reduce stock from selected lots
358
+ for (const item of items) {
359
+ if (item.lot_id) {
360
+ await client.query(
361
+ `UPDATE lots
362
+ SET remaining_quantity = remaining_quantity - $1,
363
+ status = CASE WHEN remaining_quantity - $1 <= 0 THEN 'sold_out' ELSE 'active' END,
364
+ updated_at = CURRENT_TIMESTAMP
365
+ WHERE id = $2`,
366
+ [item.net_weight, item.lot_id]
367
+ );
368
+ }
369
+ }
370
+ } else if (bill_type === 'jawaak' && is_return) {
371
+ // Sales Return: Add stock back to lots
372
+ for (const item of items) {
373
+ if (item.lot_id) {
374
+ await client.query(
375
+ `UPDATE lots
376
+ SET remaining_quantity = remaining_quantity + $1,
377
+ status = CASE WHEN remaining_quantity + $1 > 0 THEN 'active' ELSE status END,
378
+ updated_at = CURRENT_TIMESTAMP
379
+ WHERE id = $2`,
380
+ [item.net_weight, item.lot_id]
381
+ );
382
+ }
383
+ }
384
  }
385
 
386
  await client.query('COMMIT');
 
394
  'mirchi_name', ti.mirchi_name,
395
  'quality', ti.quality,
396
  'lot_id', ti.lot_id,
397
+ 'lot_number', l.lot_number,
398
  'poti_weights', ti.poti_weights,
399
  'gross_weight', ti.gross_weight,
400
  'poti_count', ti.poti_count,
 
423
  )) FILTER (WHERE p.id IS NOT NULL) as payments
424
  FROM transactions t
425
  LEFT JOIN transaction_items ti ON t.id = ti.transaction_id
426
+ LEFT JOIN lots l ON ti.lot_id = l.id
427
  LEFT JOIN expenses e ON t.id = e.transaction_id
428
  LEFT JOIN payments p ON t.id = p.transaction_id
429
  WHERE t.id = $1
src/server.js CHANGED
@@ -1,73 +1,73 @@
1
- const express = require('express');
2
- const cors = require('cors');
3
- require('dotenv').config();
4
-
5
- const partiesRouter = require('./routes/parties');
6
- const mirchiTypesRouter = require('./routes/mirchiTypes');
7
- const lotsRouter = require('./routes/lots');
8
- const transactionsRouter = require('./routes/transactions');
9
-
10
- const app = express();
11
- const PORT = process.env.PORT || 7860; // Hugging Face default port
12
-
13
- // Middleware
14
- app.use(cors());
15
- app.use(express.json());
16
- app.use(express.urlencoded({ extended: true }));
17
-
18
- // Request logging
19
- app.use((req, res, next) => {
20
- console.log(`${new Date().toISOString()} - ${req.method} ${req.path}`);
21
- next();
22
- });
23
-
24
- // Routes
25
- app.use('/api/parties', partiesRouter);
26
- app.use('/api/mirchi-types', mirchiTypesRouter);
27
- app.use('/api/lots', lotsRouter);
28
- app.use('/api/transactions', transactionsRouter);
29
-
30
- // Health check
31
- app.get('/health', (req, res) => {
32
- res.json({ status: 'ok', timestamp: new Date().toISOString() });
33
- });
34
-
35
- // Root endpoint
36
- app.get('/', (req, res) => {
37
- res.json({
38
- message: 'Pattanshetty Inventory Management API',
39
- version: '1.0.0',
40
- endpoints: {
41
- parties: '/api/parties',
42
- mirchiTypes: '/api/mirchi-types',
43
- lots: '/api/lots',
44
- transactions: '/api/transactions'
45
- }
46
- });
47
- });
48
-
49
- // Error handling middleware
50
- app.use((err, req, res, next) => {
51
- console.error('Error:', err);
52
- res.status(500).json({
53
- success: false,
54
- message: err.message || 'Internal server error'
55
- });
56
- });
57
-
58
- // 404 handler
59
- app.use((req, res) => {
60
- res.status(404).json({
61
- success: false,
62
- message: 'Route not found'
63
- });
64
- });
65
-
66
- // Start server
67
- app.listen(PORT, () => {
68
- console.log(`πŸš€ Server running on port ${PORT}`);
69
- console.log(`πŸ“ API available at http://localhost:${PORT}`);
70
- console.log(`πŸ’š Health check: http://localhost:${PORT}/health`);
71
- });
72
-
73
- module.exports = app;
 
1
+ const express = require('express');
2
+ const cors = require('cors');
3
+ require('dotenv').config();
4
+
5
+ const partiesRouter = require('./routes/parties');
6
+ const mirchiTypesRouter = require('./routes/mirchiTypes');
7
+ const lotsRouter = require('./routes/lots');
8
+ const transactionsRouter = require('./routes/transactions');
9
+
10
+ const app = express();
11
+ const PORT = process.env.PORT || 4000;
12
+
13
+ // Middleware
14
+ app.use(cors());
15
+ app.use(express.json());
16
+ app.use(express.urlencoded({ extended: true }));
17
+
18
+ // Request logging
19
+ app.use((req, res, next) => {
20
+ console.log(`${new Date().toISOString()} - ${req.method} ${req.path}`);
21
+ next();
22
+ });
23
+
24
+ // Routes
25
+ app.use('/api/parties', partiesRouter);
26
+ app.use('/api/mirchi-types', mirchiTypesRouter);
27
+ app.use('/api/lots', lotsRouter);
28
+ app.use('/api/transactions', transactionsRouter);
29
+
30
+ // Health check
31
+ app.get('/health', (req, res) => {
32
+ res.json({ status: 'ok', timestamp: new Date().toISOString() });
33
+ });
34
+
35
+ // Root endpoint
36
+ app.get('/', (req, res) => {
37
+ res.json({
38
+ message: 'Pattanshetty Inventory Management API',
39
+ version: '1.0.0',
40
+ endpoints: {
41
+ parties: '/api/parties',
42
+ mirchiTypes: '/api/mirchi-types',
43
+ lots: '/api/lots',
44
+ transactions: '/api/transactions'
45
+ }
46
+ });
47
+ });
48
+
49
+ // Error handling middleware
50
+ app.use((err, req, res, next) => {
51
+ console.error('Error:', err);
52
+ res.status(500).json({
53
+ success: false,
54
+ message: err.message || 'Internal server error'
55
+ });
56
+ });
57
+
58
+ // 404 handler
59
+ app.use((req, res) => {
60
+ res.status(404).json({
61
+ success: false,
62
+ message: 'Route not found'
63
+ });
64
+ });
65
+
66
+ // Start server
67
+ app.listen(PORT, () => {
68
+ console.log(`πŸš€ Server running on port ${PORT}`);
69
+ console.log(`πŸ“ API available at http://localhost:${PORT}`);
70
+ console.log(`πŸ’š Health check: http://localhost:${PORT}/health`);
71
+ });
72
+
73
+ module.exports = app;