n
File size: 5,577 Bytes
8008db3
52c791b
 
de9970a
52c791b
8008db3
 
52c791b
 
8008db3
52c791b
 
de9970a
52c791b
de9970a
52c791b
 
 
 
 
8008db3
 
 
 
 
 
 
 
 
b99819b
 
8008db3
 
 
52c791b
8008db3
 
 
 
52c791b
 
8008db3
 
 
 
52c791b
8008db3
 
 
52c791b
8008db3
52c791b
 
12c1a6c
52c791b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8008db3
 
52c791b
8008db3
 
 
12c1a6c
52c791b
 
 
 
 
 
8008db3
 
 
 
52c791b
8008db3
52c791b
 
 
 
 
8008db3
 
 
 
52c791b
 
8008db3
 
52c791b
 
b99819b
 
 
 
12c1a6c
b99819b
 
52c791b
 
 
b99819b
 
 
 
52c791b
 
 
b99819b
 
 
52c791b
 
b99819b
 
 
 
52c791b
b99819b
 
52c791b
b99819b
 
 
 
 
 
 
 
 
 
 
 
 
 
52c791b
12c1a6c
8008db3
12c1a6c
 
 
52c791b
12c1a6c
 
 
 
52c791b
 
 
 
8008db3
 
52c791b
 
8008db3
 
52c791b
 
fb7e70d
52c791b
8008db3
fb7e70d
 
52c791b
 
 
fb7e70d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
  Google Apps Script
  اربط هذا المشروع بملف Google Sheet الذي يحتوي على صفحة "المهام".

  ترتيب الأعمدة المعتمد:
  A = اليوم
  B = المهمة
  C = القسم
  D = الحالة

  إذا كان اسم الصفحة مختلفًا، غيّر SHEET_NAME فقط.
*/

const SHEET_NAME = "المهام";

function doGet() {
  return json_({
    ok: true,
    message: "Tasks API is running"
  });
}

function doPost(e) {
  try {
    const body = JSON.parse((e && e.postData && e.postData.contents) || "{}");
    const action = String(body.action || "").trim();

    if (action === "list") return listTasks_();
    if (action === "add") return addTask_(body);
    if (action === "update") return updateTask_(body);
    if (action === "delete") return deleteTask_(body);

    return json_({ok:false, message:"طلب غير معروف"});
  } catch (err) {
    return json_({ok:false, message: err.message || "حدث خطأ غير متوقع"});
  }
}

function sheet_() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sh = ss.getSheetByName(SHEET_NAME);
  if (!sh) throw new Error('لم يتم العثور على صفحة باسم "' + SHEET_NAME + '"');
  return sh;
}

function listTasks_() {
  const sh = sheet_();
  const lastRow = sh.getLastRow();

  if (lastRow < 2) return json_({ok:true, tasks:[]});

  const values = sh.getRange(2, 1, lastRow - 1, 4).getValues();
  const tz = Session.getScriptTimeZone() || "Asia/Riyadh";

  const tasks = values
    .map((r, i) => ({
      row: i + 2,
      date: normalizeDate_(r[0], tz),
      task: String(r[1] || "").trim(),
      department: String(r[2] || "").trim(),
      status: String(r[3] || "").trim()
    }))
    .filter(x => x.date || x.task || x.department || x.status)
    .sort((a,b) => {
      if (a.date === b.date) return b.row - a.row;
      return a.date < b.date ? 1 : -1;
    });

  return json_({ok:true, tasks:tasks});
}

function addTask_(body) {
  const date = String(body.date || "").trim();
  const task = String(body.task || "").trim();
  const department = String(body.department || "").trim();
  const status = validStatus_(body.status);

  if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) throw new Error("التاريخ غير صحيح");
  if (!task) throw new Error("اكتب المهمة");
  if (!department) throw new Error("اكتب القسم");
  if (task.length > 1000) throw new Error("نص المهمة طويل جدًا");
  if (department.length > 100) throw new Error("اسم القسم طويل جدًا");

  const sh = sheet_();
  const lock = LockService.getDocumentLock();
  lock.waitLock(10000);

  try {
    const parts = date.split("-").map(Number);
    const dateObj = new Date(parts[0], parts[1] - 1, parts[2], 12, 0, 0);
    sh.appendRow([dateObj, task, department, status]);
    const row = sh.getLastRow();
    sh.getRange(row, 1).setNumberFormat("yyyy-mm-dd");
    SpreadsheetApp.flush();
  } finally {
    lock.releaseLock();
  }

  return json_({ok:true, message:"تم حفظ المهمة بنجاح"});
}


function updateTask_(body) {
  const row = Number(body.row);
  const date = String(body.date || "").trim();
  const task = String(body.task || "").trim();
  const department = String(body.department || "").trim();
  const status = validStatus_(body.status);

  if (!Number.isInteger(row) || row < 2) throw new Error("رقم السجل غير صحيح");
  if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) throw new Error("التاريخ غير صحيح");
  if (!task) throw new Error("اكتب المهمة");
  if (!department) throw new Error("اختر القسم");

  const sh = sheet_();
  if (row > sh.getLastRow()) throw new Error("المهمة لم تعد موجودة");

  const parts = date.split("-").map(Number);
  const dateObj = new Date(parts[0], parts[1] - 1, parts[2], 12, 0, 0);

  const lock = LockService.getDocumentLock();
  lock.waitLock(10000);
  try {
    sh.getRange(row, 1, 1, 4).setValues([[dateObj, task, department, status]]);
    sh.getRange(row, 1).setNumberFormat("yyyy-mm-dd");
    SpreadsheetApp.flush();
  } finally {
    lock.releaseLock();
  }
  return json_({ok:true, message:"تم تعديل المهمة"});
}

function deleteTask_(body) {
  const row = Number(body.row);
  if (!Number.isInteger(row) || row < 2) throw new Error("رقم السجل غير صحيح");

  const sh = sheet_();
  if (row > sh.getLastRow()) throw new Error("المهمة لم تعد موجودة");

  const lock = LockService.getDocumentLock();
  lock.waitLock(10000);
  try {
    sh.deleteRow(row);
    SpreadsheetApp.flush();
  } finally {
    lock.releaseLock();
  }
  return json_({ok:true, message:"تم حذف المهمة"});
}

function validStatus_(value) {
  const status = String(value || "").trim();
  const allowed = ["", "مخطط لها", "جاري العمل", "تم الإنجاز"];
  if (!allowed.includes(status)) throw new Error("حالة المهمة غير صحيحة");
  return status;
}

function normalizeDate_(value, tz) {
  if (value instanceof Date && !isNaN(value)) {
    return Utilities.formatDate(value, tz, "yyyy-MM-dd");
  }

  const s = String(value || "").trim();
  if (!s) return "";

  // يدعم القيم النصية yyyy-mm-dd كما هي
  if (/^\d{4}-\d{2}-\d{2}$/.test(s)) return s;

  const d = new Date(s);
  if (!isNaN(d)) return Utilities.formatDate(d, tz, "yyyy-MM-dd");

  return s;
}

function json_(obj) {
  return ContentService
    .createTextOutput(JSON.stringify(obj))
    .setMimeType(ContentService.MimeType.JSON);
}