Skip to content

Commit 434cf91

Browse files
committed
delete sales
1 parent 9988227 commit 434cf91

8 files changed

Lines changed: 403 additions & 11 deletions

File tree

server/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ const providerRoutes = require("./routes/providers");
131131
const templateRoutes = require("./routes/templates");
132132
const cartRoutes = require("./routes/carts");
133133
const registerRoutes = require("./routes/registers");
134+
const adminRoutes = require("./routes/admin");
134135

135136
app.use("/api/auth", authRoutes);
136137
app.use("/api/products", productRoutes);
@@ -141,6 +142,7 @@ app.use("/api/providers", providerRoutes);
141142
app.use("/api/templates", templateRoutes);
142143
app.use("/api/carts", cartRoutes);
143144
app.use("/api/registers", registerRoutes);
145+
app.use("/api/admin", adminRoutes);
144146

145147
// Health check
146148
app.get("/api/health", (req, res) => {

server/routes/admin.js

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
const express = require("express");
2+
const router = express.Router();
3+
const mongoose = require("mongoose");
4+
const { protect, checkPermission } = require("../middleware/auth");
5+
6+
// Reset database endpoint - Admin only
7+
router.post("/reset-database", protect, async (req, res) => {
8+
try {
9+
// Check if user is admin
10+
const user = req.user;
11+
if (user.role !== "admin") {
12+
return res.status(403).json({
13+
message: "Only administrators can reset the database",
14+
});
15+
}
16+
17+
// Get all collections
18+
const collections = await mongoose.connection.db
19+
.listCollections()
20+
.toArray();
21+
22+
// Collections to preserve
23+
const preserveCollections = [
24+
"grocery_products",
25+
"categories",
26+
"users",
27+
"printtemplates",
28+
"providers",
29+
];
30+
31+
// Drop all collections except the ones to preserve
32+
for (const collection of collections) {
33+
if (!preserveCollections.includes(collection.name)) {
34+
try {
35+
await mongoose.connection.db.dropCollection(collection.name);
36+
console.log(`✓ Dropped collection: ${collection.name}`);
37+
} catch (err) {
38+
console.error(`Error dropping collection ${collection.name}:`, err);
39+
}
40+
}
41+
}
42+
43+
console.log(`✓ Database reset completed by ${user.username}`);
44+
45+
res.json({
46+
success: true,
47+
message:
48+
"Database reset successfully. Products, Users, Templates, and Providers have been preserved.",
49+
});
50+
} catch (error) {
51+
console.error("Error resetting database:", error);
52+
res.status(500).json({
53+
message: "Error resetting database",
54+
error: error.message,
55+
});
56+
}
57+
});
58+
59+
module.exports = router;

src/app/components/pos/pos.component.html

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ <h3>
275275
<div class="modal-header">
276276
<h3>
277277
<i class="fas fa-money-bill-wave"></i>
278-
{{ "POS.WITHDRAW.TITLE" | translate }}
278+
{{ "WITHDRAW.TITLE" | translate }}
279279
</h3>
280280
<button class="btn-close" (click)="closeWithdrawModal()">
281281
<i class="fas fa-times"></i>
@@ -285,7 +285,7 @@ <h3>
285285
<div class="form-group">
286286
<label for="withdrawAmount">
287287
<i class="fas fa-dollar-sign"></i>
288-
{{ "POS.WITHDRAW.AMOUNT" | translate }}
288+
{{ "WITHDRAW.AMOUNT" | translate }}
289289
</label>
290290
<div class="input-wrapper">
291291
<span class="currency">$</span>
@@ -303,14 +303,14 @@ <h3>
303303
<div class="form-group">
304304
<label for="withdrawReason">
305305
<i class="fas fa-comment-alt"></i>
306-
{{ "POS.WITHDRAW.REASON" | translate }}
306+
{{ "WITHDRAW.REASON" | translate }}
307307
</label>
308308
<textarea
309309
id="withdrawReason"
310310
[(ngModel)]="withdrawReason"
311311
class="form-control"
312312
rows="3"
313-
[placeholder]="'POS.WITHDRAW.REASON_PLACEHOLDER' | translate"
313+
[placeholder]="'WITHDRAW.REASON_PLACEHOLDER' | translate"
314314
></textarea>
315315
</div>
316316
</div>
@@ -324,7 +324,7 @@ <h3>
324324
(click)="confirmWithdraw()"
325325
>
326326
<i class="fas fa-check"></i>
327-
{{ "POS.WITHDRAW.CONFIRM" | translate }}
327+
{{ "WITHDRAW.CONFIRM" | translate }}
328328
</button>
329329
</div>
330330
</div>

src/app/components/settings/settings.component.html

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
11
<div class="page-container">
2-
<app-page-title
3-
[title]="'SETTINGS.TITLE' | translate"
4-
[description]="'SETTINGS.DESCRIPTION' | translate"
5-
>
6-
</app-page-title>
7-
82
<section class="card setting-section">
93
<div class="setting-header">
104
<div class="header-actions">
@@ -280,4 +274,72 @@ <h3>{{ "SETTINGS.QR_BADGE.TITLE" | translate }}</h3>
280274
</button>
281275
</div>
282276
</section>
277+
278+
<!-- Reset Database Section (Admin Only) -->
279+
@if (isAdmin) {
280+
<section class="card reset-db-section danger-zone">
281+
<h3>{{ "SETTINGS.RESET_DB.TITLE" | translate }}</h3>
282+
<p class="section-description danger-description">
283+
{{ "SETTINGS.RESET_DB.DESCRIPTION" | translate }}
284+
</p>
285+
286+
<div class="reset-db-content">
287+
<div class="warning-box">
288+
<i class="fas fa-exclamation-circle"></i>
289+
<p>{{ "SETTINGS.RESET_DB.WARNING" | translate }}</p>
290+
</div>
291+
292+
@if (!showResetDBConfirm) {
293+
<button
294+
class="btn btn-danger"
295+
(click)="toggleResetDBConfirm()"
296+
title="Reset database (admin only)"
297+
>
298+
<i class="fas fa-redo-alt"></i>
299+
{{ "SETTINGS.RESET_DB.BUTTON" | translate }}
300+
</button>
301+
} @else {
302+
<div class="reset-confirmation-box">
303+
<p class="confirmation-label">
304+
{{ "SETTINGS.RESET_DB.CONFIRM_LABEL" | translate }}
305+
</p>
306+
<input
307+
type="text"
308+
[(ngModel)]="resetConfirmationText"
309+
placeholder="{{
310+
'SETTINGS.RESET_DB.CONFIRM_PLACEHOLDER' | translate
311+
}}"
312+
class="confirmation-input"
313+
(keyup.enter)="resetDatabase()"
314+
/>
315+
<div class="confirmation-actions">
316+
<button
317+
class="btn btn-secondary"
318+
(click)="toggleResetDBConfirm()"
319+
[disabled]="resettingDatabase"
320+
>
321+
<i class="fas fa-times"></i>
322+
{{ "GLOBAL.CANCEL" | translate }}
323+
</button>
324+
<button
325+
class="btn btn-danger"
326+
(click)="resetDatabase()"
327+
[disabled]="
328+
resettingDatabase ||
329+
resetConfirmationText.toLowerCase() !== 'confirm'
330+
"
331+
>
332+
@if (resettingDatabase) {
333+
<i class="fas fa-spinner fa-spin"></i>
334+
} @else {
335+
<i class="fas fa-exclamation-triangle"></i>
336+
}
337+
{{ "SETTINGS.RESET_DB.CONFIRM_BUTTON" | translate }}
338+
</button>
339+
</div>
340+
</div>
341+
}
342+
</div>
343+
</section>
344+
}
283345
</div>

src/app/components/settings/settings.component.scss

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,3 +458,170 @@
458458
}
459459
}
460460
}
461+
462+
// Reset Database Section
463+
.reset-db-section {
464+
&.danger-zone {
465+
border-left: 4px solid $danger;
466+
background: rgba(245, 101, 101, 0.05);
467+
468+
h3 {
469+
color: $danger;
470+
}
471+
472+
.danger-description {
473+
color: #d32f2f;
474+
font-weight: $font-weight-medium;
475+
}
476+
}
477+
478+
.reset-db-content {
479+
display: flex;
480+
flex-direction: column;
481+
gap: $spacing-md;
482+
}
483+
484+
.warning-box {
485+
display: flex;
486+
align-items: flex-start;
487+
gap: $spacing-md;
488+
padding: $spacing-md;
489+
background: #fff3cd;
490+
border: 1px solid #ffc107;
491+
border-radius: 8px;
492+
493+
i {
494+
color: #ff6b6b;
495+
font-size: 1.25rem;
496+
flex-shrink: 0;
497+
margin-top: 0.125rem;
498+
}
499+
500+
p {
501+
margin: 0;
502+
color: #856404;
503+
font-size: $font-size-sm;
504+
}
505+
}
506+
507+
.btn-danger {
508+
background: $danger;
509+
color: white;
510+
border: none;
511+
padding: 0.75rem 1.5rem;
512+
border-radius: 8px;
513+
cursor: pointer;
514+
font-weight: $font-weight-semibold;
515+
display: inline-flex;
516+
align-items: center;
517+
gap: 0.5rem;
518+
transition: all 0.2s;
519+
520+
&:hover:not(:disabled) {
521+
background: darken($danger, 10%);
522+
transform: translateY(-1px);
523+
box-shadow: 0 4px 12px rgba($danger, 0.3);
524+
}
525+
526+
&:active:not(:disabled) {
527+
transform: translateY(0);
528+
}
529+
530+
&:disabled {
531+
opacity: 0.5;
532+
cursor: not-allowed;
533+
}
534+
535+
i {
536+
font-size: $font-size-base;
537+
}
538+
}
539+
540+
.reset-confirmation-box {
541+
display: flex;
542+
flex-direction: column;
543+
gap: $spacing-md;
544+
padding: $spacing-md;
545+
background: var(--bg-tertiary);
546+
border: 2px solid $danger;
547+
border-radius: 8px;
548+
549+
.confirmation-label {
550+
font-weight: $font-weight-semibold;
551+
color: var(--text-primary);
552+
margin: 0;
553+
}
554+
555+
.confirmation-input {
556+
padding: 0.75rem $spacing-md;
557+
border: 1px solid var(--border-color);
558+
border-radius: 6px;
559+
background: white;
560+
color: var(--text-primary);
561+
font-size: $font-size-base;
562+
font-weight: $font-weight-medium;
563+
font-family: "Courier New", monospace;
564+
565+
&:focus {
566+
outline: none;
567+
border-color: $danger;
568+
box-shadow: 0 0 0 2px rgba($danger, 0.1);
569+
}
570+
571+
&::placeholder {
572+
color: var(--text-muted);
573+
}
574+
}
575+
576+
.confirmation-actions {
577+
display: flex;
578+
gap: $spacing-md;
579+
justify-content: flex-end;
580+
581+
.btn {
582+
padding: 0.625rem 1.25rem;
583+
border: none;
584+
border-radius: 6px;
585+
cursor: pointer;
586+
font-weight: $font-weight-semibold;
587+
display: flex;
588+
align-items: center;
589+
gap: 0.5rem;
590+
transition: all 0.2s;
591+
font-size: $font-size-sm;
592+
593+
&:disabled {
594+
opacity: 0.5;
595+
cursor: not-allowed;
596+
}
597+
}
598+
599+
.btn-secondary {
600+
background: var(--bg-primary);
601+
color: var(--text-primary);
602+
border: 1px solid var(--border-color);
603+
604+
&:hover:not(:disabled) {
605+
background: var(--bg-tertiary);
606+
border-color: $gray-300;
607+
}
608+
}
609+
610+
.btn-danger {
611+
background: $danger;
612+
color: white;
613+
padding: 0.625rem 1.25rem;
614+
615+
&:hover:not(:disabled) {
616+
background: darken($danger, 10%);
617+
transform: translateY(-1px);
618+
box-shadow: 0 4px 12px rgba($danger, 0.3);
619+
}
620+
621+
&:active:not(:disabled) {
622+
transform: translateY(0);
623+
}
624+
}
625+
}
626+
}
627+
}

0 commit comments

Comments
 (0)