This commit is contained in:
@@ -43,8 +43,8 @@ namespace Aberwyn.Controllers
|
|||||||
var dto = new BudgetDto
|
var dto = new BudgetDto
|
||||||
{
|
{
|
||||||
Id = period.Id,
|
Id = period.Id,
|
||||||
Year = period.Year,
|
Year = period.Year ?? 0,
|
||||||
Month = period.Month,
|
Month = period.Month ?? 0,
|
||||||
Categories = period.Categories
|
Categories = period.Categories
|
||||||
.OrderBy(cat => cat.Order)
|
.OrderBy(cat => cat.Order)
|
||||||
.Select(cat => new BudgetCategoryDto
|
.Select(cat => new BudgetCategoryDto
|
||||||
@@ -74,6 +74,57 @@ namespace Aberwyn.Controllers
|
|||||||
return StatusCode(500, $"Fel: {ex.Message} \n{ex.StackTrace}");
|
return StatusCode(500, $"Fel: {ex.Message} \n{ex.StackTrace}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("byname/{name}")]
|
||||||
|
public async Task<IActionResult> GetBudgetByName(string name)
|
||||||
|
{
|
||||||
|
var period = await _context.BudgetPeriods
|
||||||
|
.Include(p => p.Categories)
|
||||||
|
.ThenInclude(c => c.Items)
|
||||||
|
.FirstOrDefaultAsync(p => p.Name != null && p.Name.ToLower() == name.ToLower());
|
||||||
|
|
||||||
|
if (period == null)
|
||||||
|
{
|
||||||
|
return Ok(new BudgetDto
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
Categories = new List<BudgetCategoryDto>()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var dto = new BudgetDto
|
||||||
|
{
|
||||||
|
Id = period.Id,
|
||||||
|
Name = period.Name,
|
||||||
|
Year = period.Year ?? 0,
|
||||||
|
Month = period.Month ?? 0,
|
||||||
|
Categories = period.Categories
|
||||||
|
.OrderBy(cat => cat.Order)
|
||||||
|
.Select(cat => new BudgetCategoryDto
|
||||||
|
{
|
||||||
|
Id = cat.Id,
|
||||||
|
Name = cat.Name,
|
||||||
|
Color = cat.Color,
|
||||||
|
Items = cat.Items
|
||||||
|
.OrderBy(i => i.Order)
|
||||||
|
.Select(i => new BudgetItemDto
|
||||||
|
{
|
||||||
|
Id = i.Id,
|
||||||
|
Name = i.Name,
|
||||||
|
Amount = i.Amount,
|
||||||
|
IsExpense = i.IsExpense,
|
||||||
|
IncludeInSummary = i.IncludeInSummary,
|
||||||
|
BudgetItemDefinitionId = i.BudgetItemDefinitionId,
|
||||||
|
PaymentStatus = i.PaymentStatus
|
||||||
|
}).ToList()
|
||||||
|
}).ToList()
|
||||||
|
};
|
||||||
|
|
||||||
|
return Ok(dto);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[HttpPut("updatePaymentStatus")]
|
[HttpPut("updatePaymentStatus")]
|
||||||
public IActionResult UpdatePaymentStatus([FromBody] PaymentStatusUpdateDto dto)
|
public IActionResult UpdatePaymentStatus([FromBody] PaymentStatusUpdateDto dto)
|
||||||
{
|
{
|
||||||
@@ -199,11 +250,37 @@ namespace Aberwyn.Controllers
|
|||||||
[HttpPost]
|
[HttpPost]
|
||||||
public async Task<IActionResult> CreatePeriod([FromBody] BudgetPeriod newPeriod)
|
public async Task<IActionResult> CreatePeriod([FromBody] BudgetPeriod newPeriod)
|
||||||
{
|
{
|
||||||
_context.BudgetPeriods.Add(newPeriod);
|
if (!string.IsNullOrWhiteSpace(newPeriod.Name))
|
||||||
await _context.SaveChangesAsync();
|
{
|
||||||
return CreatedAtAction(nameof(GetBudget), new { year = newPeriod.Year, month = newPeriod.Month }, newPeriod);
|
var existingNamed = await _context.BudgetPeriods
|
||||||
|
.FirstOrDefaultAsync(p => p.Name != null && p.Name.ToLower() == newPeriod.Name.ToLower());
|
||||||
|
|
||||||
|
if (existingNamed != null)
|
||||||
|
return Conflict("En budget med detta namn finns redan.");
|
||||||
|
|
||||||
|
_context.BudgetPeriods.Add(newPeriod);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
return Ok(new { id = newPeriod.Id });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newPeriod.Year.HasValue && newPeriod.Month.HasValue)
|
||||||
|
{
|
||||||
|
var existing = await _context.BudgetPeriods
|
||||||
|
.FirstOrDefaultAsync(p => p.Year == newPeriod.Year && p.Month == newPeriod.Month);
|
||||||
|
|
||||||
|
if (existing != null)
|
||||||
|
return Conflict("En budget för denna månad finns redan.");
|
||||||
|
|
||||||
|
_context.BudgetPeriods.Add(newPeriod);
|
||||||
|
await _context.SaveChangesAsync();
|
||||||
|
return Ok(new { id = newPeriod.Id });
|
||||||
|
}
|
||||||
|
|
||||||
|
return BadRequest("Varken namn eller år/månad angivet.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[HttpPut("item/{id}")]
|
[HttpPut("item/{id}")]
|
||||||
public async Task<IActionResult> UpdateItem(int id, [FromBody] BudgetItem updatedItem)
|
public async Task<IActionResult> UpdateItem(int id, [FromBody] BudgetItem updatedItem)
|
||||||
{
|
{
|
||||||
@@ -330,19 +407,12 @@ namespace Aberwyn.Controllers
|
|||||||
return BadRequest("Ogiltig data.");
|
return BadRequest("Ogiltig data.");
|
||||||
|
|
||||||
var period = await _context.BudgetPeriods
|
var period = await _context.BudgetPeriods
|
||||||
.FirstOrDefaultAsync(p => p.Year == newCategoryDto.Year && p.Month == newCategoryDto.Month);
|
.FirstOrDefaultAsync(p => p.Id == newCategoryDto.BudgetPeriodId);
|
||||||
|
|
||||||
if (period == null)
|
if (period == null)
|
||||||
{
|
return NotFound("Kunde inte hitta angiven budgetperiod.");
|
||||||
period = new BudgetPeriod
|
|
||||||
{
|
|
||||||
Year = newCategoryDto.Year,
|
|
||||||
Month = newCategoryDto.Month
|
|
||||||
};
|
|
||||||
_context.BudgetPeriods.Add(period);
|
|
||||||
await _context.SaveChangesAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// 🔁 fortsätt som tidigare…
|
||||||
var definition = await _context.BudgetCategoryDefinitions
|
var definition = await _context.BudgetCategoryDefinitions
|
||||||
.FirstOrDefaultAsync(d => d.Name.ToLower() == newCategoryDto.Name.ToLower());
|
.FirstOrDefaultAsync(d => d.Name.ToLower() == newCategoryDto.Name.ToLower());
|
||||||
|
|
||||||
@@ -372,6 +442,8 @@ namespace Aberwyn.Controllers
|
|||||||
return Ok(new { id = category.Id });
|
return Ok(new { id = category.Id });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[HttpDelete("category/{id}")]
|
[HttpDelete("category/{id}")]
|
||||||
public async Task<IActionResult> DeleteCategory(int id)
|
public async Task<IActionResult> DeleteCategory(int id)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,6 +14,14 @@ namespace Aberwyn.Controllers
|
|||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Route("budget/{name}")]
|
||||||
|
public IActionResult Index(string name)
|
||||||
|
{
|
||||||
|
ViewBag.BudgetName = name;
|
||||||
|
return View();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// För fallback när ingen månad/år anges
|
// För fallback när ingen månad/år anges
|
||||||
[Route("budget")]
|
[Route("budget")]
|
||||||
public IActionResult Index()
|
public IActionResult Index()
|
||||||
|
|||||||
1060
Aberwyn/Migrations/20250708102137_AddNameToBudgetPeriod.Designer.cs
generated
Normal file
1060
Aberwyn/Migrations/20250708102137_AddNameToBudgetPeriod.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
Aberwyn/Migrations/20250708102137_AddNameToBudgetPeriod.cs
Normal file
19
Aberwyn/Migrations/20250708102137_AddNameToBudgetPeriod.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Aberwyn.Migrations
|
||||||
|
{
|
||||||
|
public partial class AddNameToBudgetPeriod : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1063
Aberwyn/Migrations/20250708102224_AddNameToBudgetPeriod2.Designer.cs
generated
Normal file
1063
Aberwyn/Migrations/20250708102224_AddNameToBudgetPeriod2.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
26
Aberwyn/Migrations/20250708102224_AddNameToBudgetPeriod2.cs
Normal file
26
Aberwyn/Migrations/20250708102224_AddNameToBudgetPeriod2.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Aberwyn.Migrations
|
||||||
|
{
|
||||||
|
public partial class AddNameToBudgetPeriod2 : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<string>(
|
||||||
|
name: "Name",
|
||||||
|
table: "BudgetPeriods",
|
||||||
|
type: "longtext",
|
||||||
|
nullable: true)
|
||||||
|
.Annotation("MySql:CharSet", "utf8mb4");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "Name",
|
||||||
|
table: "BudgetPeriods");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1063
Aberwyn/Migrations/20250708104331_MakeYearMonthNullable.Designer.cs
generated
Normal file
1063
Aberwyn/Migrations/20250708104331_MakeYearMonthNullable.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
51
Aberwyn/Migrations/20250708104331_MakeYearMonthNullable.cs
Normal file
51
Aberwyn/Migrations/20250708104331_MakeYearMonthNullable.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Aberwyn.Migrations
|
||||||
|
{
|
||||||
|
public partial class MakeYearMonthNullable : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "Year",
|
||||||
|
table: "BudgetPeriods",
|
||||||
|
type: "int",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "int");
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "Month",
|
||||||
|
table: "BudgetPeriods",
|
||||||
|
type: "int",
|
||||||
|
nullable: true,
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "int");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "Year",
|
||||||
|
table: "BudgetPeriods",
|
||||||
|
type: "int",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0,
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "int",
|
||||||
|
oldNullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AlterColumn<int>(
|
||||||
|
name: "Month",
|
||||||
|
table: "BudgetPeriods",
|
||||||
|
type: "int",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: 0,
|
||||||
|
oldClrType: typeof(int),
|
||||||
|
oldType: "int",
|
||||||
|
oldNullable: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -226,13 +226,16 @@ namespace Aberwyn.Migrations
|
|||||||
.ValueGeneratedOnAdd()
|
.ValueGeneratedOnAdd()
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<int>("Month")
|
b.Property<int?>("Month")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Name")
|
||||||
|
.HasColumnType("longtext");
|
||||||
|
|
||||||
b.Property<int>("Order")
|
b.Property<int>("Order")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.Property<int>("Year")
|
b.Property<int?>("Year")
|
||||||
.HasColumnType("int");
|
.HasColumnType("int");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|||||||
@@ -7,9 +7,11 @@ namespace Aberwyn.Models
|
|||||||
public class BudgetPeriod
|
public class BudgetPeriod
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int Year { get; set; }
|
public int? Year { get; set; }
|
||||||
public int Month { get; set; }
|
public int? Month { get; set; }
|
||||||
public int Order { get; set; }
|
public int Order { get; set; }
|
||||||
|
public string? Name { get; set; }
|
||||||
|
|
||||||
public List<BudgetCategory> Categories { get; set; } = new();
|
public List<BudgetCategory> Categories { get; set; } = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,8 +64,9 @@ namespace Aberwyn.Models
|
|||||||
public class BudgetDto
|
public class BudgetDto
|
||||||
{
|
{
|
||||||
public int Id { get; set; }
|
public int Id { get; set; }
|
||||||
public int Year { get; set; }
|
public string? Name { get; set; }
|
||||||
public int Month { get; set; }
|
public int? Year { get; set; }
|
||||||
|
public int? Month { get; set; }
|
||||||
public int Order { get; set; }
|
public int Order { get; set; }
|
||||||
|
|
||||||
public List<BudgetCategoryDto> Categories { get; set; } = new();
|
public List<BudgetCategoryDto> Categories { get; set; } = new();
|
||||||
@@ -78,7 +81,7 @@ namespace Aberwyn.Models
|
|||||||
public int Order { get; set; }
|
public int Order { get; set; }
|
||||||
public int? BudgetCategoryDefinitionId { get; set; }
|
public int? BudgetCategoryDefinitionId { get; set; }
|
||||||
|
|
||||||
|
public int? BudgetPeriodId { get; set; }
|
||||||
public int Year { get; set; }
|
public int Year { get; set; }
|
||||||
public int Month { get; set; }
|
public int Month { get; set; }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
ViewData["Title"] = "Budget";
|
ViewData["Title"] = "Budget";
|
||||||
}
|
}
|
||||||
|
|
||||||
<div ng-app="budgetApp" ng-controller="BudgetController" class="budget-page" ng-if="!loading">
|
<div ng-app="budgetApp" ng-controller="BudgetController">
|
||||||
<div class="budget-header" style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px;">
|
<div class="budget-header" style="display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 16px;">
|
||||||
<div class="month-nav-bar" style="display: flex; align-items: center; gap: 10px; position: relative;">
|
<div class="month-nav-bar" style="display: flex; align-items: center; gap: 10px; position: relative;">
|
||||||
<button class="nav-button" ng-click="previousMonth()">←</button>
|
<button class="nav-button" ng-click="previousMonth()">←</button>
|
||||||
@@ -190,14 +190,22 @@
|
|||||||
<div>Summa</div>
|
<div>Summa</div>
|
||||||
<div class="amount">{{ getCategorySum(cat) | number:0 }}</div>
|
<div class="amount">{{ getCategorySum(cat) | number:0 }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="no-data" ng-if="!loading && budget && budget.categories.length === 0">
|
|
||||||
Det finns ingen budgetdata för vald månad ({{ selectedMonth }}/{{ selectedYear }}).
|
|
||||||
<button ng-click="copyPreviousMonthSafe()">[Test] Kopiera föregående</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="no-data" ng-if="!loading && budget && budget.categories.length === 0">
|
||||||
|
<p>Det finns ingen budgetdata för
|
||||||
|
<strong>{{ budget.name || (selectedMonth + '/' + selectedYear) }}</strong>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div style="margin-top: 10px;">
|
||||||
|
<button ng-click="createEmptyBudget()" style="margin-right: 10px;">
|
||||||
|
Skapa ny budget
|
||||||
|
</button>
|
||||||
|
<button ng-click="copyPreviousMonthSafe()">
|
||||||
|
Kopiera föregående månad
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="add-item-popup" ng-show="addPopupVisible" ng-style="addPopupStyle" ng-class="{ 'above': addPopupAbove }">
|
<div class="add-item-popup" ng-show="addPopupVisible" ng-style="addPopupStyle" ng-class="{ 'above': addPopupAbove }">
|
||||||
<label>Typ:</label>
|
<label>Typ:</label>
|
||||||
<select ng-model="addPopupData.newItemType">
|
<select ng-model="addPopupData.newItemType">
|
||||||
@@ -262,8 +270,10 @@
|
|||||||
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />
|
||||||
<script>
|
<script>
|
||||||
window.initialYear = @ViewBag.Year;
|
window.initialYear = @(ViewBag.Year ?? "null");
|
||||||
window.initialMonth = @ViewBag.Month;
|
window.initialMonth = @(ViewBag.Month ?? "null");
|
||||||
|
window.initialName = "@(ViewBag.BudgetName ?? "")";
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<script src="~/js/budget.js"></script>
|
<script src="~/js/budget.js"></script>
|
||||||
<script src="~/js/budget-dragdrop.js"></script>
|
<script src="~/js/budget-dragdrop.js"></script>
|
||||||
@@ -6,6 +6,7 @@ app.controller('BudgetController', function ($scope, $http) {
|
|||||||
$scope.error = null;
|
$scope.error = null;
|
||||||
$scope.menuOpen = false;
|
$scope.menuOpen = false;
|
||||||
$scope.chartMode = "pie";
|
$scope.chartMode = "pie";
|
||||||
|
const initialName = window.initialName;
|
||||||
|
|
||||||
$scope.monthNames = ["Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December"];
|
$scope.monthNames = ["Januari", "Februari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December"];
|
||||||
$scope.getMonthName = function (month) {
|
$scope.getMonthName = function (month) {
|
||||||
@@ -15,6 +16,7 @@ app.controller('BudgetController', function ($scope, $http) {
|
|||||||
$scope.selectedYear = window.initialYear || new Date().getFullYear();
|
$scope.selectedYear = window.initialYear || new Date().getFullYear();
|
||||||
$scope.selectedMonth = window.initialMonth || new Date().getMonth() + 1;
|
$scope.selectedMonth = window.initialMonth || new Date().getMonth() + 1;
|
||||||
|
|
||||||
|
|
||||||
$scope.tempMonth = $scope.monthNames[$scope.selectedMonth - 1];
|
$scope.tempMonth = $scope.monthNames[$scope.selectedMonth - 1];
|
||||||
$scope.tempYear = $scope.selectedYear;
|
$scope.tempYear = $scope.selectedYear;
|
||||||
$scope.selectedMonthName = $scope.getMonthName($scope.selectedMonth);
|
$scope.selectedMonthName = $scope.getMonthName($scope.selectedMonth);
|
||||||
@@ -140,10 +142,21 @@ app.controller('BudgetController', function ($scope, $http) {
|
|||||||
$scope.loading = true;
|
$scope.loading = true;
|
||||||
$scope.error = null;
|
$scope.error = null;
|
||||||
$scope.budget = null;
|
$scope.budget = null;
|
||||||
|
$scope.budgetNotFound = false;
|
||||||
|
|
||||||
$http.get(`/api/budget/${$scope.selectedYear}/${$scope.selectedMonth}`)
|
const useName = typeof initialName === 'string' && initialName !== "null" && initialName !== "";
|
||||||
|
|
||||||
|
let url = "";
|
||||||
|
if (useName) {
|
||||||
|
url = `/api/budget/byname/${initialName}`;
|
||||||
|
} else {
|
||||||
|
url = `/api/budget/${$scope.selectedYear}/${$scope.selectedMonth}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
$http.get(url)
|
||||||
.then(function (response) {
|
.then(function (response) {
|
||||||
const raw = response.data;
|
const raw = response.data;
|
||||||
|
|
||||||
if (raw && raw.Categories) {
|
if (raw && raw.Categories) {
|
||||||
const categories = raw.Categories.map(cat => ({
|
const categories = raw.Categories.map(cat => ({
|
||||||
id: cat.Id,
|
id: cat.Id,
|
||||||
@@ -151,6 +164,7 @@ app.controller('BudgetController', function ($scope, $http) {
|
|||||||
color: cat.Color,
|
color: cat.Color,
|
||||||
editing: false,
|
editing: false,
|
||||||
allowDrag: false,
|
allowDrag: false,
|
||||||
|
order: cat.Order ?? 0,
|
||||||
items: (cat.Items || []).map((item, index) => {
|
items: (cat.Items || []).map((item, index) => {
|
||||||
const definition = $scope.itemDefinitions.find(d => d.id === item.BudgetItemDefinitionId || d.Id === item.BudgetItemDefinitionId);
|
const definition = $scope.itemDefinitions.find(d => d.id === item.BudgetItemDefinitionId || d.Id === item.BudgetItemDefinitionId);
|
||||||
return {
|
return {
|
||||||
@@ -165,23 +179,35 @@ app.controller('BudgetController', function ($scope, $http) {
|
|||||||
paymentStatus: item.PaymentStatus
|
paymentStatus: item.PaymentStatus
|
||||||
};
|
};
|
||||||
}).sort((a, b) => a.order - b.order)
|
}).sort((a, b) => a.order - b.order)
|
||||||
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
$scope.budget = {
|
$scope.budget = {
|
||||||
id: raw.Id,
|
id: raw.Id,
|
||||||
|
name: raw.Name || null,
|
||||||
year: raw.Year,
|
year: raw.Year,
|
||||||
month: raw.Month,
|
month: raw.Month,
|
||||||
categories: categories.sort((a, b) => a.order - b.order)
|
categories: categories.sort((a, b) => a.order - b.order)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.budgetNotFound = false;
|
||||||
|
|
||||||
|
if (!useName) {
|
||||||
|
$scope.selectedMonthName = $scope.getMonthName($scope.selectedMonth);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
$scope.budget = { categories: [] };
|
$scope.budget = { categories: [] };
|
||||||
|
$scope.budgetNotFound = true;
|
||||||
}
|
}
|
||||||
$scope.selectedMonthName = $scope.getMonthName($scope.selectedMonth);
|
|
||||||
})
|
})
|
||||||
.catch(function (error) {
|
.catch(function (error) {
|
||||||
if (error.status === 404) {
|
if (error.status === 404) {
|
||||||
$scope.budget = { categories: [] };
|
$scope.budget = {
|
||||||
|
name: useName ? initialName : null,
|
||||||
|
year: useName ? null : $scope.selectedYear,
|
||||||
|
month: useName ? null : $scope.selectedMonth,
|
||||||
|
categories: []
|
||||||
|
};
|
||||||
|
$scope.budgetNotFound = true;
|
||||||
} else {
|
} else {
|
||||||
$scope.error = "Kunde inte ladda budgetdata.";
|
$scope.error = "Kunde inte ladda budgetdata.";
|
||||||
$scope.showToast("Fel vid laddning av budgetdata", true);
|
$scope.showToast("Fel vid laddning av budgetdata", true);
|
||||||
@@ -194,6 +220,7 @@ app.controller('BudgetController', function ($scope, $http) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
$scope.saveCategory = function (category) {
|
$scope.saveCategory = function (category) {
|
||||||
if (category.newItemName && category.newItemAmount) {
|
if (category.newItemName && category.newItemAmount) {
|
||||||
const newItem = {
|
const newItem = {
|
||||||
@@ -811,6 +838,28 @@ $scope.addItemFromDefinition = function (cat) {
|
|||||||
return cat.items.some(i => i.isExpense);
|
return cat.items.some(i => i.isExpense);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.createEmptyBudget = function () {
|
||||||
|
if (!$scope.budget || !$scope.budget.name) {
|
||||||
|
$scope.showToast("Ogiltigt budgetnamn.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dto = {
|
||||||
|
name: $scope.budget.name
|
||||||
|
};
|
||||||
|
|
||||||
|
$http.post('/api/budget', dto)
|
||||||
|
.then(() => {
|
||||||
|
$scope.showToast("Ny budget skapad.");
|
||||||
|
$scope.loadBudget(); // ladda om efter skapandet
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error("Fel vid skapande:", error);
|
||||||
|
$scope.showToast("Kunde inte skapa budget.");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
$scope.drawCategoryChart = function () {
|
$scope.drawCategoryChart = function () {
|
||||||
const ctx = document.getElementById("expenseChart");
|
const ctx = document.getElementById("expenseChart");
|
||||||
if (!ctx || !$scope.budget?.categories) return;
|
if (!ctx || !$scope.budget?.categories) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user