OpenSource решение за уеб фактуриране и не само- Odoo

faktura_dhstudio
От standalone приложение към съвременно cloud решение с Odoo
От дълго време се налагаше да преминем към нова система за фактуриране. До скоро ползвах standalone приложение, но с преминаването към евро и необходимостта от достъп от различни локации се наложи спешно да намеря алтернатива.

Защо не standalone приложения?
Разгледах няколко варианта, включително безплатното решение Microinvest Invoice Pro, но не исках да се ограничавам със standalone Windows приложения. Търсех облачно решение с достъп от всяко устройство и място.
Решението: Odoo

Odoo е безплатна бизнес софтуерна система (ERP) с отворен код, която обединява всички основни бизнес процеси на едно място: счетоводство, фактуриране, управление на клиенти (CRM), продажби, склад, човешки ресурси, проекти и много други.
Защо Odoo?
Целта беше проста – да мога да генерирам фактури и отчети от всяка локация, по всяко време. Системата трябваше да:

Работи с евро и лева едновременно
Генерира ДДС справки за внасяне и възстановяване
Създава професионални PDF фактури
Бъде достъпна онлайн от всяко устройство
Не изисква инсталация на отделни компютри

Персонализация
Разработих два custom модула специално за българския пазар:

Български фактури – форматирани според местните изисквания
ДДС анализ и справки – автоматично изчисляване на ДДС за внасяне/възстановяване с визуални отчети

Модулите са написани на Python и са лесни за адаптиране. Ако някой се нуждае от тях, с удоволствие ще ги споделя.
Препоръка
Изключително препоръчвам Odoo за фактуриране, счетоводство и бизнес управление! Системата е като Lego конструктор – започвате с необходимите модули и добавяте функционалност според нуждите си.
Odoo = Lego за счетоводство! 🚀
dds_spravka

PS: Всички изображения като фактури, статистика са примерни докато тествах адоните.

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Да промениш номерацията на цитатите в статия за 1 секунда

vba_scripting_nauchna_statiq

При писане на статия се наложи промяна на литературата и респективно – на номерацията на цитатите. Проблемът е, че само източниците в литературата са 23 броя, а в статията има още много повече цитати. За целта, с помощта на едно просто VBA скриптче за Word, в което описваме стар номер и нов номер, за 1 секунда се преномерират всички цитати в статията и списъкът с литература.

Какво прави скриптчето?
В нашия случай трябва да се променят така: [2] -> [1], [3] -> [2], [4] -> [3], [6] -> [4].
За целта скриптчето прави точно 2 конверсии, т.е.:
[2] -> [], [3] -> [], [4] -> [], [6] -> [].
Умишлено временният стринг е такъв, за да се редуцира вероятността да го има в текста към 0.
Втората конверсия е: [] -> [1], [] -> [2], [] -> [3], [] -> [4].
За да въведем скриптчето в Word, натискаме Alt + F11, след това Insert > Module.
Въвеждаме го там и го изпълняваме с F5.
Ииии – voilà! Имаме си нова номерация в литературата и обновени цитати в статията.

Това беше първата версия на литературата, като се наложи да се коригира последователността:

[1] Pavlova, N. & Marchev, D. Application of artificial intelligence in generation of stem tasks, KNOWLEDGE –International Journal, Vol.66.2, pp. 185-191. 2024

[2] Желязкова, М. STEM в контекста на компетентностния подход в образованието, Образование и технологии, Vol. 13, стр. 206-212. 2022
[3] Кожухаров, М. Въведение в изкуствения интелект, Тракийски университет, ДИПКУ. Стара Загора, 2025, ISBN 978-954-691-114-8
[4] Кожухарова, Д. От дигитална компетентност към дигитална креативност. Академично издателство, Тракийски университет. Стара Загора, 2020, ISBN 978-954-338-166-1

Новата последователност на литературата:

[2] Желязкова, М. STEM в контекста на компетентностния подход в образованието, Образование и технологии, Vol. 13, стр. 206-212. 2022
[3] Кожухаров, М. Въведение в изкуствения интелект, Тракийски университет, ДИПКУ. Стара Загора, 2025, ISBN 978-954-691-114-8
[4] Кожухарова, Д. От дигитална компетентност към дигитална креативност. Академично издателство, Тракийски университет. Стара Загора, 2020, ISBN 978-954-338-166-1
[6] Рашева-Мерджанова, Я. Трансформация на ключовите компетентности на съвременния учител в контекста на социалното взаимодействие. – Стратегии на образователната и научната политика. № 3, с. 243 – 253, 2010

След изпълнение на скриптчето:
[1] Желязкова, М. STEM в контекста на компетентностния подход в образованието, Образование и технологии, Vol. 13, стр. 206-212. 2022
[2] Кожухаров, М. Въведение в изкуствения интелект, Тракийски университет, ДИПКУ. Стара Загора, 2025, ISBN 978-954-691-114-8
[3] Кожухарова, Д. От дигитална компетентност към дигитална креативност. Академично издателство, Тракийски университет. Стара Загора, 2020, ISBN 978-954-338-166-1
[4] Рашева-Мерджанова, Я. Трансформация на ключовите компетентности на съвременния учител в контекста на социалното взаимодействие. – Стратегии на образователната и научната политика. № 3, с. 243 – 253, 2010

Ето го и скриптчето:
Sub MultiReplaceOptimized_Unique()

Dim pairs As Variant
Dim i As Long
Dim oldNum As String, newNum As String
Dim find1 As String, rep1 As String
Dim find2 As String, rep2 As String
Dim rng As Range

' Wywejdame w lqwata chast na masiwa stariq nomer, a w dqsnata nowiqt. Created by Martin Petrov and ChatGPT
pairs = Array( _
Array("2", "1"), _
Array("3", "2"), _
Array("4", "3"), _
Array("6", "4"), _
Array("7", "5"), _
Array("12", "6"), _
Array("9", "7"), _
Array("15", "8"), _
Array("8", "9"), _
Array("14", "10"), _
Array("16", "11"), _
Array("17", "12"), _
Array("10", "13"), _
Array("19", "14"), _
Array("18", "15"), _
Array("20", "16"), _
Array("1", "17"), _
Array("13", "18"), _
Array("11", "19"), _
Array("21", "20"), _
Array("22", "21"), _
Array("23", "22"), _
Array("24", "23") _
)

For i = LBound(pairs) To UBound(pairs)

oldNum = pairs(i)(0)
newNum = pairs(i)(1)

find1 = "[" & oldNum & "]"
rep1 = "[]"

Set rng = ActiveDocument.Content
With rng.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = find1
.Replacement.Text = rep1
.Wrap = wdFindStop
.Execute Replace:=wdReplaceAll
End With

Next i

For i = LBound(pairs) To UBound(pairs)

newNum = pairs(i)(1)

find2 = "[]"
rep2 = "[" & newNum & "]"

Set rng = ActiveDocument.Content
With rng.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = find2
.Replacement.Text = rep2
.Wrap = wdFindStop
.Execute Replace:=wdReplaceAll
End With

Next i

MsgBox "MP Replacer v 1.0. Ready", vbInformation

End Sub

Изключителни благодарности на проф. д.н. Наталия Христова Павлова

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Инсталиране на Windows 11

Преди две години с Вики почистихме и инсталирахме тази машинка с M$ Windows 10.
Днес дойде ред отново за профилактика и инсталиране на M$ Windows 11, тъй като поддръжката на Windows 10 приключва на 14.10.2025 г.

Друго си е, когато сам си почистиш, форматираш, инсталираш и конфигурираш своята M$ Windows 11 машинка.

Имах около 89 127 381 723 въпроса – това как, онова защо, но усещането да си жив GPT не е никак лошо. 🙂

Светли дни идват за DH Studio!

За да заобиколим задължителния M$ Account, стартирахме cmd с Shift + F10 и въведохме:

start ms-cxh:localonly

Така създаваме локален потребител.

Всичко вървеше добре, но при инсталация на Windows 11 на дъното ASRock Steel Legend B450 излезе съобщение, че системата не отговаря на изискванията:

This PC doesn’t currently meet Windows 11 system requirements
This PC doesn’t meet the minimum system requirements to install this version of Windows.
For more information, visit: https://aka.ms/WindowsSysReq

👉 Решението включва:

Активиране на Intel PTT (TPM 2.0):

Влизане в Advanced Mode

Секция Security

Активиране на Intel Platform Trust Technology (PTT)

Позволяване на Secure Boot:

Секция Security

Secure Boot Mode → активиране на Secure Boot

Защо Windows 11?
Заради игрите. Повечето нови заглавия вече са създадени за най-масовата ОС, а в момента това е Windows 11.

И все пак – Windows си остава боза. 😄

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Прехвърляне на Roundcube mail от един хостинг на друг

При прехвърлянето е генериран списък, но писмата все още не са били прехвърлени.
Затова писмата се отварят със съдържанието си, но като заглавие се изписва „message unavailable“.

Решение:
Изтриване на кеша и повторно генериране на индекса:

bash
Copy
Edit
rm -f courierimapuiddb
Още един проблем беше, че има папки, които съществуват в стария Roundcube, но не се появяват в новия.

Решение:
Ръчно да се добавят във файла courierimapsubscribed:

Copy
Edit
INBOX.Archives
INBOX.Archives.2018
INBOX.Archives.2019
INBOX.Archives.2020
INBOX.Archives.2021
INBOX.Archives.2022
INBOX.Drafts
INBOX.Junk
INBOX.Sent
INBOX.alcomet
INBOX.spam
INBOX.Trash

testy .

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Monit мониторинг на incus container

cat /etc/monit/monitrc

CHECK PROGRAM apache2_dobromir_status WITH PATH "/root/monit/check_apache_run.sh dobromir"
IF CONTENT = "apache2 not work" THEN EXEC "/usr/bin/incus exec dobromir --- systemctl start apache2"

CHECK PROGRAM mysql_dobromir_status WITH PATH "/root/monit/check_mysql_run.sh dobromir"
IF CONTENT = "mysql not work" THEN EXEC "/usr/bin/incus exec dobromir --- systemctl start mysql"

CHECK PROGRAM apache2_max_process_dobromir_status WITH PATH "/root/monit/check_apache_max_process.sh dobromir 30"
IF CONTENT = "apache2 max process" THEN EXEC "/usr/bin/incus exec dobromir --- systemctl restart apache2"

root@#:~/monit# cat check_apache_max_process.sh
#!/bin/bash

CONTAINER_NAME=$1
MAX_PROCESS=$2

process_count=$(/usr/bin/incus exec "$CONTAINER_NAME" --- pgrep -c apache2)

# Проверка на броя на процесите
if [ "$process_count" -gt $MAX_PROCESS ]; then
printf "apache2 max process"
exit 1
else
printf "apache2 no max process"
exit 0
fi

root@#:~/monit# cat check_apache_run.sh
#!/bin/bash

CONTAINER_NAME=$1

apache_status=$(/usr/bin/incus exec "$CONTAINER_NAME" --- systemctl is-active apache2)

if [ "$apache_status" != "active" ]; then
printf "apache2 not work"
exit 1
else
printf "apache2 work"
exit 0
fi

root@#:~/monit# cat check_mysql_run.sh
#!/bin/bash

CONTAINER_NAME=$1

apache_status=$(/usr/bin/incus exec "$CONTAINER_NAME" --- systemctl is-active mysql)

if [ "$apache_status" != "active" ]; then
printf "mysql not work"
exit 1
else
printf "mysql work"
exit 0
fi

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Ремонт на стоп/габарит на Nissan Qashqai J10 (Valeo B003339B Led module REV12 R)

Ремонт на стоп/габарит на Nissan Qashqai J10
Ремонт на стоп/габарит на Nissan Qashqai J10 (Valeo B003339B Led module REV12 R)

Явно всеки втори Qashqai J10 има проблем с вода в стоповете, което води до окисляване и изгаряне на платката с елементи, респективно спират да работят стопът и габаритът. Идеята на този пост е да бъде в помощ.

Необходими елементи:

Светодиоди: SMD CLEAR RED 3528 PLCC2 /червен; 660nm; 1.9V; 400mcd; 120/
Кондензатори: SMD C0603 1nF/50V X7R
Резистори: SMD R1206 100R 5%

С няколко думи, необходимо е да се заменят повредените елементи. В конкретния случай това бяха светодиодите, кондензаторите и резисторите. След като ги замених, всичко заработи отлично. Има две положения – при едното светват габаритите с по-слаба сила, а при другото същите LED-ове светят с по-голяма сила.

За запояването на SMD компонентите използвах тинол паста, както и обикновен поялник с тънък тинол. Тъй като в момента нямах налична станция за горещ въздух, импровизирах такава за случая, като използвах пистолет за горещ въздух с прецизно регулиране на температурата и една фуния от алуминиева плака :) Разбира се, не е същото като станцията, но се представи достатъчно добре, за да успея да премахна старите елементи и да запоя новите.

Хубаво е, преди да се монтира работещата платка, да се изолира компрометираният стоп, за да се избегне ново проникване на влага.

Успех!

P.S.: Специални благодарности на Минчо и Христина от Антекс – с тяхната професионална измервателна апаратура успяхме да измерим малкото останали работещи елементи, за да знаем с какво да бъдат заменени изгорелите.

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

php8

Fatal error: Uncaught TypeError: count(): Argument #1 ($value) must be of type Countable|array, null given in file.php:206 Stack trace: #0 {main} thrown in file.php on line 206

преди
$num_results=count($r);
след
$num_results=count((array)$r);

--------------------------

VN:F [1.9.22_1171]
Rating: 0.0/5 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Личен Блог на Мартин Петров