< Summary

Class:WinSolutions.Sveta.Server.Data.DataModel.Entities.Movement
Assembly:WinSolutions.Sveta.Server
File(s):/opt/dev/sveta_api_build/WinSolutions.Sveta.Server/Data/DataModel/Entities/Movement.cs
Covered lines:180
Uncovered lines:60
Coverable lines:240
Total lines:408
Line coverage:75% (180 of 240)
Covered branches:66
Total branches:172
Branch coverage:38.3% (66 of 172)

Metrics

MethodLine coverage Branch coverage
get_DtCreated()0%100%
get_ParentId()100%100%
get_Parent()100%100%
get_ChildrenId()0%100%
get_Children()100%100%
get_MovementType()100%100%
get_Items()100%100%
get_Customer()100%100%
get_Supplier()100%100%
get_Receiver()100%100%
get_Sender()100%100%
get_PrepaimentPercent()100%100%
get_PrepaimentSum()100%100%
get_Notes()100%100%
get_SupplierTransferDate()100%100%
get_MovementStatus()100%100%
get_DocumentNumber()100%100%
get_Attachment()100%100%
get_TotalAttachmentSize()0%100%
get_MovementAttachments()0%100%
get_DeliveryType()100%100%
get_MovementStatusJournals()0%100%
get_MinOrderSum()100%100%
get_Actions()100%100%
get_Statuses()0%100%
.ctor()100%100%
CreateBaseOn(...)100%100%
CloneThis(...)100%100%
GetPositionStatus(...)0%0%
FillActions(...)100%75%
CreateDocumentNumber(...)100%64.28%
ReCalculate()100%100%
UpdatePriceInDraft()93.33%75%
AddItem(...)100%62.5%
CheckCanWorkWithMovement(...)90%30.43%
CheckEditable(...)100%16.66%

File(s)

/opt/dev/sveta_api_build/WinSolutions.Sveta.Server/Data/DataModel/Entities/Movement.cs

#LineLine coverage
 1using System;
 2using System.Collections.Generic;
 3using System.ComponentModel.DataAnnotations;
 4using System.ComponentModel.DataAnnotations.Schema;
 5using System.Linq;
 6using System.Text;
 7using System.Threading.Tasks;
 8using TidVtbc;
 9using WinSolutions.Sveta.Server.Data.DataModel.Kinds;
 10using WinSolutions.Sveta.Server.Domain;
 11
 12namespace WinSolutions.Sveta.Server.Data.DataModel.Entities
 13{
 14    public class Movement : ExternalRecord, ITrackableRecord
 15    {
 16        /// <summary>
 17        ///Дата создания документа
 18        /// </summary>
 19        [Required]
 20        //[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
 021        public DateTime DtCreated { get; set; } = DateTime.UtcNow;
 22
 99923        public long? ParentId { get; set; }
 24
 25        /// <summary>
 26        /// Родительский документ
 27        /// </summary>
 34928        public Movement Parent { get; set; }
 29
 030        public long? ChildrenId { get; set; }
 31        /// <summary>
 32        /// Дочерний документ
 33        /// </summary>
 16934        public Movement Children { get; set; }
 35
 36        /// <summary>
 37        /// Тип прихода
 38        /// </summary>
 39        [Required]
 154640        public MovementType MovementType { get; set; }
 41
 42        /// <summary>
 43        ///Состав заказа
 44        /// </summary>
 415145        public List<MovementItem> Items { get; set; }
 46
 47
 48        /// <summary>
 49        /// Заказчик
 50        /// </summary>
 51        [Required]
 164952        public Contragent Customer { get; set; }
 53
 54        /// <summary>
 55        /// Поставщик
 56        /// </summary>
 57        [Required]
 89558        public Contragent Supplier { get; set; }
 59
 60        /// <summary>
 61        /// Получатель
 62        /// </summary>
 63        [Required]
 162164        public Department Receiver { get; set; }
 65
 66        /// <summary>
 67        /// Склад отправитель
 68        /// </summary>
 132069        public Department Sender { get; set; }
 70
 71        /// <summary>
 72        /// Размер предоплаты %
 73        /// </summary>
 74        [Required]
 75        [Column(TypeName = "decimal(18,2)")]
 48776        public decimal PrepaimentPercent { get; set; }
 77
 78        /// <summary>
 79        /// Сумма предоплаты
 80        /// </summary>
 81        [Required]
 82        [Column(TypeName = "decimal(18,2)")]
 59083        public decimal PrepaimentSum { get; set; }
 84
 85        /// <summary>
 86        /// Комментарии к документам
 87        /// </summary>
 112788        public List<MovementNote> Notes { get; set; }
 89
 90        //public string Comment { get; set; }
 91
 92        /// <summary>
 93        /// Дата передачи поставщику
 94        /// </summary>
 26095        public DateTime? SupplierTransferDate { get; set; }
 96
 97        /// <summary>
 98        /// Статус
 99        /// </summary>
 100      /*  [Obsolete]
 101        public MovementsStatus Status { get; set; }*/
 102        [Required]
 18239103        public MovementStatus MovementStatus { get; set; }
 104
 105        /// <summary>
 106        /// Номер документа ORXXXXXXX/SHXXXXXXXX
 107        /// </summary>
 108        [Required]
 1083109        public string DocumentNumber { get; set; }
 110
 111        /// <summary>
 112        /// Вложение - устарело - используем MovementAttachment
 113        /// </summary>
 114        [Obsolete]
 740115        public string Attachment { get; set; }
 116
 117        /// <summary>
 118        /// Сумма занимаемого места на диске приложенных файлов
 119        /// </summary>
 0120        public long TotalAttachmentSize { get; set; }
 121
 122        /// <summary>
 123        /// Список вложений
 124        /// </summary>
 0125        public List<MovementAttachment> MovementAttachments { get; set; }
 126
 127        /// <summary>
 128        /// Тип доставки
 129        /// </summary>
 1123130        public DeliveryType DeliveryType { get; set; }
 131
 132        /// <summary>
 133        /// История действий с документом
 134        /// </summary>
 0135        public List<MovementStatusJournal> MovementStatusJournals { get; set; }
 136
 137        /// <summary>
 138        /// Минимальная сумма заказа на момент отправки в обработки
 139        /// </summary>
 188140        public decimal MinOrderSum { get; set; }
 141
 142        /// <summary>
 143        /// Доступные действия над документом
 144        /// </summary>
 282145        [NotMapped] public List<MovementAction> Actions { get; set; }
 0146        [NotMapped] public long[] Statuses { get; set; }
 147
 807148        public Movement() { }
 72149        public Movement CreateBaseOn(MovementType kind, MovementStatus status, RecordsState recstate) => new Movement
 72150            {
 72151                ParentId = this.Id,
 72152                Parent = this,
 72153                Items = this.Items.CloneItems(),
 72154                Customer = this.Customer,
 72155                Supplier = this.Supplier,
 72156                Receiver = this.Receiver,
 72157                Sender = this.Sender,
 72158                PrepaimentPercent = this.PrepaimentPercent,
 72159                PrepaimentSum = this.PrepaimentSum,
 72160                SupplierTransferDate = DateTime.UtcNow,
 72161                MovementStatus = status,
 72162                RecState = recstate,
 72163                MovementType = kind,
 72164                Notes = new List<MovementNote>(),
 72165                MinOrderSum = this.MinOrderSum,
 72166                DeliveryType = this.DeliveryType
 72167            };
 2168        public Movement CloneThis(MovementStatus status, RecordsState recstate) => new Movement
 2169        {
 2170            ParentId = this.ParentId,
 2171            Parent = this.Parent,
 2172            Items = this.Items.CloneItems(),
 2173            Customer = this.Customer,
 2174            Supplier = this.Supplier,
 2175            Receiver = this.Receiver,
 2176            Sender = this.Sender,
 2177            PrepaimentPercent = this.PrepaimentPercent,
 2178            PrepaimentSum = this.PrepaimentSum,
 2179            SupplierTransferDate = DateTime.MinValue,
 2180            MovementStatus = status,
 2181            RecState = recstate,
 2182            MovementType = this.MovementType,
 2183            Notes = new List<MovementNote>(),
 2184            DeliveryType = this.DeliveryType
 2185        };
 186        /// <summary>
 187        /// Возвращает числовое соответствие статуса документа в зависимости от переданной позиции
 188        /// </summary>
 189        /// <param name="movementStatus">номер статуса</param>
 190        /// <param name="position">номер позиции</param>
 191        /// <returns></returns>
 0192        public int GetPositionStatus(int position) => position switch
 0193        {
 0194            0 => this.MovementStatus.Id switch
 0195            {
 0196                (long) MovementsStatus.OrderDraft => 1,
 0197                (long) MovementsStatus.InQueue => 2,
 0198                (long) MovementsStatus.SupplierReject => -1,
 0199                (long) MovementsStatus.CustomerReject => -1,
 0200                (long) MovementsStatus.Reject => -1,
 0201                _ => 4
 0202            },
 0203            // блок отгрузки
 0204            1 => this.MovementStatus.Id switch
 0205            {
 0206                (long) MovementsStatus.ShipmentDraft => 1,
 0207                (long) MovementsStatus.PaymentAwaiting => 1,
 0208                (long) MovementsStatus.Picking => 2,
 0209                (long) MovementsStatus.ReadyForShipment => 3,
 0210                (long) MovementsStatus.SupplierReject => -1,
 0211                (long) MovementsStatus.CustomerReject => -1,
 0212                (long) MovementsStatus.Reject => -1,
 0213                (long) MovementsStatus.ShipmentReject => -1,
 0214                (long) MovementsStatus.Correction => -2,
 0215                _ => 4
 0216            },
 0217            // блок прихода
 0218            2 => this.MovementStatus.Id switch
 0219            {
 0220                (long) MovementsStatus.Shipped => 0,
 0221                (long) MovementsStatus.Received => 4,
 0222                (long) MovementsStatus.CustomerReject => -1,
 0223                _ => 0
 0224            },
 0225            // блок оплаты
 0226            3 => this.MovementStatus.Id switch
 0227            {
 0228                (long) MovementsStatus.PaymentAwaiting => 5,
 0229                (long) MovementsStatus.Picking => 6,
 0230                _ => 0
 0231            },
 0232            // блок претензии
 0233            4 => this.MovementStatus.Id switch
 0234            {
 0235                (long) MovementsStatus.ClaimInProgress => -3,
 0236                (long) MovementsStatus.ClaimDeclined => -5,
 0237                (long) MovementsStatus.ClaimAccepted => -4,
 0238                _ => 0
 0239            },
 0240            _ => 0,
 0241        };
 242
 243        /// <summary>
 244        /// Заполняет список доступных действий с документом
 245        /// </summary>
 246        /// <param name="allActions">Список доступных действий</param>
 247        /// <param name="contragentKindId">Идентификатор типа контрагента</param>
 248        /// <param name="Roles">Список ролей пользователя</param>
 249        public void FillActions(List<MovementRouteAction> allActions, long contragentKindId, List<string> Roles)
 118250        {
 118251            long owner = contragentKindId switch
 118252            {
 118253                (long) ContragentKind.Retailer => 1,
 118254                (long) ContragentKind.Wholesaler => 2,
 118255                (long) ContragentKind.Platform => 3,
 118256                _ => 1
 118257            };
 258
 118259            this.Actions = allActions
 39530260                .Where(d => d.OwnerActionId == owner && d.StatusId == this.MovementStatus.Id)
 828261                .Select(d => new MovementAction
 828262                {
 828263                    Caption = d.Caption.Trim(),
 828264                    Type = d.Type.Trim(),
 828265                    Code = d.Code.Trim(),
 828266                    Action = d.Action?.Replace("{id}", this.Id.ToString().Trim())?
 828267                        .Replace("{parentId}", this.ParentId?.ToString())
 828268                })
 828269                .Where(d => !string.IsNullOrEmpty(this.Attachment) || !d.Code.ToUpper().Equals("GetAttachment".ToUpper()
 827270                .Where(d => this.MovementStatus.Id != (long)MovementsStatus.ReadyForShipment ||
 827271                            ((this.DeliveryType?.Code.Equals("Pickup") ?? true) ? !d.Code.Equals("Deliver") : !d.Code.Eq
 827272                .Where(d => this.DeliveryType?.Id == (long)DeliveryTypeKind.Delivery || !d.Code.Equals("PrintTn"))
 826273                .Where(d => Roles != null && !Roles.Contains("dd_sys_low_level") ||
 826274                            d.Type.ToUpper().Equals("GET"))
 118275                .ToList();
 118276        }
 277        /// <summary>
 278        /// Формирует номер документа по формату
 279        /// </summary>
 280        /// <param name="envName">Имя окружения</param>
 281        /// <returns></returns>
 282        public void CreateDocumentNumber(string envName) =>
 169283            this.DocumentNumber = this.MovementType.Id switch
 169284        {
 169285            (long) MovementKind.Order => $"OR{this.Id.ToString("D8")}",
 169286            (long) MovementKind.Shipment => ((Func<string>)(() =>
 241287            {
 241288                return envName.ToLower() switch
 241289                {
 241290                    "development" => TID.New(7801, 220, (int) this.Id + 100_000_000).StringWithDashes,
 241291                    "qa" => TID.New(7801, 220, (int) this.Id + 200_000_000).StringWithDashes,
 241292                    "stage" => TID.New(7801, 220, (int) this.Id + 300_000_000).StringWithDashes,
 241293                    _ => TID.New(7801, 220, (int) this.Id).StringWithDashes,
 241294                };
 241295            }))(),
 169296            (long) MovementKind.Arrival => $"RE{this.Id.ToString("D8")}",
 169297            _ => ""
 169298        };
 299
 300        /// <summary>
 301        /// Перерасчет суммы предоплаты
 302        /// </summary>
 303        /// <returns></returns>
 75304        public void ReCalculate() => this.PrepaimentSum =
 152305                (this.Items.Sum((i => (i.Price * i.Quantity))) * this.PrepaimentPercent) / 100;
 306
 307        /// <summary>
 308        /// Обновление цен в документе
 309        /// </summary>
 310        /// <param name="movement">Документ</param>
 311        /// <param name="itemList">Список заказанных товаров</param>
 312        /// <returns>List&lt;MovementItem&gt;</returns>
 313        public void UpdatePriceInDraft()
 72314        {
 144315            SupplyContract contract = this.Customer.ContractsAsBuyer.FirstOrDefault(d => !d.IsDeleted
 144316                                                                                             && d.Seller.Id ==
 144317                                                                                             this.Supplier.Id
 144318                                                                                             && d.BeginDate <= DateTime.
 144319                                                                                             && d.EndDate >= DateTime.Ut
 72320                                      ?? throw new ArgumentException(
 72321                                          $"Не найден действующий контракт для" +
 72322                                          $" покупателя {this.Customer?.ShortName} и продавца {this.Supplier?.ShortName}
 323
 0324            if (this.Items.Count == 0) return;
 72325            Parallel.ForEach(this.Items, item =>
 148326            {
 148327                item.CalculatePrice(this.Receiver.Cluster, contract.RatioForCalculations);
 148328            });
 72329        }
 330
 331        public void AddItem(MovementItem mItem, RecordsState active)
 73332         {
 333             MovementItem movementItem;
 73334             this.Items ??= new List<MovementItem>();
 81335             if (this.Items != null && this.Items.Any(d => d.Good.Id == mItem.Good.Id))
 4336             {
 8337                 movementItem = this.Items.FirstOrDefault(d => d.Good.Id == mItem.Good.Id)
 4338                                ?? throw new ArgumentException($"Позиция в документе для товара {mItem.Good.Id} не найде
 4339                 movementItem.Quantity = mItem.Quantity;
 8340                 this.Items[this.Items.FindIndex(d => d.Good.Id == mItem.Good.Id)] = movementItem;
 4341             }
 342             else
 69343             {
 138344                 SupplyContract contract = this.Customer.ContractsAsBuyer.FirstOrDefault(d => !d.IsDeleted
 138345                                                                                              && d.Seller.Id ==
 138346                                                                                              this.Supplier.Id
 138347                                                                                              && d.BeginDate <=
 138348                                                                                              DateTime.UtcNow
 138349                                                                                              && d.EndDate >=
 138350                                                                                              DateTime.UtcNow)
 69351                                           ?? throw new ArgumentException(
 69352                                               $"Ошибка в расчете стоимости при добавлении позиции в документ. Не найден
 353                 // иначе добавим товар в заявку
 69354                 movementItem = new MovementItem
 69355                 {
 69356                     Good = mItem.Good,
 69357                     Price = 0,
 69358                     Quantity = mItem.Quantity,
 69359                     RecState = active,
 69360                     //MovementId = this.Id
 69361                 };
 69362                 movementItem.CalculatePrice(this.Receiver.Cluster, contract.RatioForCalculations);
 69363                 this.Items.Add(movementItem);
 69364             }
 73365         }
 366        public bool CheckCanWorkWithMovement(long contragentKindId, long contragentId, bool isOwner, List<Department> de
 367        , bool isAnonym = false, Guid anonymUuid = default) =>
 132368            this.MovementType.Id switch
 132369        {
 132370            (long)MovementKind.Order => ((Func<bool>)(() =>
 263371            {
 263372                return contragentKindId switch
 263373                {
 263374                    (long) ContragentKind.Retailer => this.Customer.Id == contragentId
 0375                                                      && (isOwner || departments.Any(x => x.Id == this.Receiver.Id))
 263376                     && (!isAnonym || this.GUID.Equals(anonymUuid)),
 263377                    (long) ContragentKind.Wholesaler => false,
 263378                    (long) ContragentKind.Platform => true,
 263379                    _ => false,
 263380                };
 263381            }))(),
 132382            (long)MovementKind.Shipment => ((Func<bool>)(() =>
 133383            {
 133384                return contragentKindId switch
 133385                {
 133386                    (long) ContragentKind.Wholesaler => (this.Supplier.Id == contragentId ||
 133387                                                         this.Customer.Id == contragentId)
 0388                                                        && (isOwner || departments.Any(x=>x.Id == this.Sender.Id)),
 133389                    (long) ContragentKind.Retailer => this.Customer.Id == contragentId &&
 133390                                                      (this.MovementStatus.Id != (long) MovementsStatus.ShipmentDraft)
 0391                                                      && (isOwner || departments.Any(x => x.Id == this.Receiver.Id)),
 133392                    (long) ContragentKind.Platform => true,
 133393                    _ => false,
 133394                };
 133395            }))(),
 132396            _ => false
 132397        };
 398
 399        public bool CheckEditable(MovementStatus draftStatus) =>
 70400            this.MovementType.Id switch
 70401            {
 70402                (long) MovementKind.Order => this.MovementStatus.Id == draftStatus.Id,
 70403                (long) MovementKind.Shipment => this.MovementStatus.Id == draftStatus.Id ||
 70404                                                this.MovementStatus.Id == (long) MovementsStatus.Correction,
 70405                _ => false
 70406            };
 407    }
 408}