buhanka-finance-app 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.html +32 -24
  2. package/package.json +1 -1
package/index.html CHANGED
@@ -228,7 +228,7 @@ tr.subtotal>td:first-child{color:var(--accent);box-shadow:inset 3px 0 0 var(--ac
228
228
 
229
229
  <script>
230
230
  /* ============================================================ БУХАНКА · Финансы v2 ============================================================ */
231
- const APP_VERSION='3.5';
231
+ const APP_VERSION='3.6';
232
232
  const SCHEMA=3; /* версия структуры данных; растёт при доработках */
233
233
  const STORE_KEY='buhanka_finance_v9';/* НЕ МЕНЯТЬ НИКОГДА — иначе данные «слетят» при обновлении файла */
234
234
  const LEGACY_KEYS=['buhanka_finance_v8','buhanka_finance_v7','buhanka_finance_v6','buhanka_finance_v5'];
@@ -1187,7 +1187,7 @@ function renderCF(C){
1187
1187
 
1188
1188
  /* ── 2. наличные по точкам ── */
1189
1189
  const m=primaryMonth(), lk=isLocked(m);
1190
- html+=`<div class="panel"><div class="hd"><h3>Наличные по точкам · ${m}</h3><div class="spacer"></div>
1190
+ html+=`<div class="panel"><div class="hd"><h3>Наличные по точкам и карты · ${m}</h3><div class="spacer"></div>
1191
1191
  ${lk?'<span class="tag lock">🔒 закрыт</span>':'<span class="muted small">факт — то, что реально в кассе точки</span>'}</div>
1192
1192
  <div class="bd" style="padding:0"><div class="tbl-wrap"><table>
1193
1193
  <thead><tr><th>Точка / счёт</th><th class="num" style="width:130px">На начало</th><th class="num">Приход нал.</th><th class="num">Расход нал.</th>
@@ -1205,31 +1205,39 @@ function renderCF(C){
1205
1205
  <td class="num neg">${c.out?fmt(c.out):'—'}</td><td class="num" style="font-weight:600">${fmt(c.calc)}</td>
1206
1206
  <td class="num"><input class="money" ${lk?'disabled':''} value="${fv!=null&&fv!==''?fmtNum(fv):''}" placeholder="—" style="width:120px" onchange="cashFactSet('${m}','${p}',this.value)"></td>
1207
1207
  <td class="num ${diff==null?'muted':Math.abs(diff)<1?'pos':'neg'}">${diff==null?'—':(diff>0?'+':'')+fmt(diff)}</td></tr>`; });
1208
- const cashAccs=ST.accounts.filter(isCashLike);
1209
- if(cashAccs.length){
1210
- html+=`<tr class="header"><td colspan="7" style="color:var(--muted2);font-size:11px;text-transform:uppercase;letter-spacing:.05em;padding-top:14px">Наличные счета и карты</td></tr>`;
1211
- const mi2=MONTHS.indexOf(m);
1212
- cashAccs.forEach(a=>{
1213
- const open=accountBalance(a,mi2-1), close=accountBalance(a,mi2);
1214
- let inc=0,out=0;
1215
- (ST.operations||[]).filter(o=>o.month===m&&isCashOp(o)).forEach(o=>{ const d=accDelta(o,a.name);
1216
- if(d>0)inc+=d; else out-=d; });
1217
- const key='acc:'+a.name; const fv=(ST.cashFact[m]||{})[key]; const has=!(fv==null||fv==='');
1218
- const diff=has?Number(fv)-close:null;
1219
- if(has){ tF+=Number(fv); tCf+=close; nF++; }
1220
- tS+=open; tI+=inc; tO+=out; tC+=close;
1221
- html+=`<tr><td class="muted">${esc(a.name)}</td><td class="num muted">${fmt(open)}</td>
1222
- <td class="num pos">${inc?fmt(inc):'—'}</td><td class="num neg">${out?fmt(out):'—'}</td>
1223
- <td class="num" style="font-weight:600">${fmt(close)}</td>
1208
+ /* итог по точкам */
1209
+ const tD_pt = nF ? tF-tCf : null;
1210
+ html+=`<tr class="subtotal"><td>Итого по точкам</td><td class="num">${fmt(tS)}</td><td class="num">${fmt(tI)}</td>
1211
+ <td class="num">${fmt(tO)}</td><td class="num">${fmt(tC)}</td><td class="num">${nF?fmt(tF):'—'}</td>
1212
+ <td class="num ${tD_pt==null?'':Math.abs(tD_pt)<1?'pos':'neg'}">${tD_pt==null?'—':(tD_pt>0?'+':'')+fmt(tD_pt)}</td></tr>`;
1213
+
1214
+ const mi2=MONTHS.indexOf(m);
1215
+ const accFlow=(a)=>{ let inc=0,out=0;
1216
+ (ST.operations||[]).filter(o=>o.month===m&&isCashOp(o)).forEach(o=>{ const d=accDelta(o,a.name); if(d>0)inc+=d; else out-=d; });
1217
+ return {open:accountBalance(a,mi2-1), close:accountBalance(a,mi2), inc, out}; };
1218
+
1219
+ /* контрольная строка: счёт «наличные» целиком должен совпасть с суммой по точкам */
1220
+ ST.accounts.filter(a=>accType(a)==='cash').forEach(a=>{ const f=accFlow(a); const d=f.close-tC;
1221
+ html+=`<tr><td class="muted">Счёт «${esc(a.name)}» — всего</td><td class="num muted">${fmt(f.open)}</td>
1222
+ <td class="num pos">${f.inc?fmt(f.inc):'—'}</td><td class="num neg">${f.out?fmt(f.out):'—'}</td>
1223
+ <td class="num" style="font-weight:600">${fmt(f.close)}</td><td class="num muted small">сверка с точками</td>
1224
+ <td class="num ${Math.abs(d)<1?'pos':'neg'}">${Math.abs(d)<1?'сходится':(d>0?'+':'')+fmt(d)}</td></tr>`; });
1225
+
1226
+ /* карты — отдельные счета, в кассу точек не входят */
1227
+ const cards=ST.accounts.filter(a=>accType(a)==='card');
1228
+ if(cards.length){
1229
+ html+=`<tr class="header"><td colspan="7" style="color:var(--muted2);font-size:11px;text-transform:uppercase;letter-spacing:.05em;padding-top:14px">Карты — отдельные счета</td></tr>`;
1230
+ cards.forEach(a=>{ const f=accFlow(a); const key='acc:'+a.name;
1231
+ const fv=(ST.cashFact[m]||{})[key]; const has=!(fv==null||fv==='');
1232
+ const diff=has?Number(fv)-f.close:null;
1233
+ html+=`<tr><td>${esc(a.name)}</td><td class="num muted">${fmt(f.open)}</td>
1234
+ <td class="num pos">${f.inc?fmt(f.inc):'—'}</td><td class="num neg">${f.out?fmt(f.out):'—'}</td>
1235
+ <td class="num" style="font-weight:600">${fmt(f.close)}</td>
1224
1236
  <td class="num"><input class="money" ${lk?'disabled':''} value="${has?fmtNum(fv):''}" placeholder="—" style="width:120px" onchange="cashFactSet('${m}','${key}',this.value)"></td>
1225
1237
  <td class="num ${diff==null?'muted':Math.abs(diff)<1?'pos':'neg'}">${diff==null?'—':(diff>0?'+':'')+fmt(diff)}</td></tr>`; });
1226
1238
  }
1227
- const tD=nF?tF-tCf:null;
1228
- html+=`<tr class="subtotal"><td>Итого</td><td class="num">${fmt(tS)}</td><td class="num">${fmt(tI)}</td><td class="num">${fmt(tO)}</td>
1229
- <td class="num">${fmt(tC)}</td><td class="num">${nF?fmt(tF):'—'}</td>
1230
- <td class="num ${tD==null?'':Math.abs(tD)<1?'pos':'neg'}">${tD==null?'—':(tD>0?'+':'')+fmt(tD)}</td></tr>
1231
- </tbody></table></div></div>
1232
- <p class="hint" style="padding:0 15px 12px;margin:0">По точкам: «На начало» в первом месяце учёта вводится вручную, дальше подставляется факт предыдущего месяца. Приход и расход — наличные операции и переводы, привязанные к точке. Ниже — наличные счета и карты целиком, по данным всех операций и переводов. Расхождение считается только там, где заполнен факт${nF?` (заполнено ${nF})`:''}.</p></div>`;
1239
+ html+=`</tbody></table></div></div>
1240
+ <p class="hint" style="padding:0 15px 12px;margin:0">Наличные — это деньги на точках: «На начало» в первом месяце учёта вводится вручную, дальше подставляется факт предыдущего месяца. Строка «Счёт "Наличные" — всего» сверяет остаток счёта с суммой по точкам: если сходится, вся касса разнесена по точкам. Карты — отдельные счета, в кассу точек не входят; перевод из кассы на карту уменьшает наличку точки.</p></div>`;
1233
1241
 
1234
1242
  /* ── 3. деньги по дням в разрезе статей ── */
1235
1243
  if(agg){ html+=`<div class="note">Таблица по дням доступна при выборе конкретного месяца — сейчас выбран период «${P}».</div>`; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "buhanka-finance-app",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Buhanka bakery finance dashboard — single-file web app",
5
5
  "license": "MIT",
6
6
  "files": [