From f6dde36a633e6d302224631df72a70bd25350595 Mon Sep 17 00:00:00 2001 From: jopster Date: Thu, 4 Apr 2024 20:07:36 +0200 Subject: [PATCH] Aufteilung & Logging --- __manifest__.py | 9 +- models/__pycache__/dss.cpython-311.pyc | Bin 35503 -> 66214 bytes models/dss.py | 721 +++++++++++++++++++++---- security/ir.model.access.csv | 8 + static/images/tree_r.png | Bin 0 -> 241 bytes static/images/tree_ud.png | Bin 0 -> 207 bytes views/.mc.menu | 379 +++++++++++++ views/dss_addstructures.xml | 72 +++ views/dss_ads.xml | 324 +++++++++++ views/{dss.xml => dss_contracts.xml} | 180 +----- views/dss_mediafiles.xml | 72 +++ views/dss_projects.xml | 164 ++++++ views/dss_projectstate.xml | 55 ++ views/dss_systemtypen.xml | 60 ++ views/dss_texts.xml | 68 +++ views/mainsystem_view.xml | 415 +++++++------- views/menu.xml | 172 ++++++ 17 files changed, 2225 insertions(+), 474 deletions(-) create mode 100644 static/images/tree_r.png create mode 100644 static/images/tree_ud.png create mode 100644 views/.mc.menu create mode 100755 views/dss_addstructures.xml create mode 100755 views/dss_ads.xml rename views/{dss.xml => dss_contracts.xml} (70%) create mode 100755 views/dss_mediafiles.xml create mode 100755 views/dss_projects.xml create mode 100755 views/dss_projectstate.xml create mode 100755 views/dss_systemtypen.xml create mode 100755 views/dss_texts.xml diff --git a/__manifest__.py b/__manifest__.py index 09451e7..6c4b2e5 100755 --- a/__manifest__.py +++ b/__manifest__.py @@ -14,7 +14,14 @@ 'security/groups.xml', 'security/ir.model.access.csv', 'views/menu.xml', - 'views/dss.xml', + 'views/dss_projectstate.xml', + 'views/dss_systemtypen.xml', + 'views/dss_projects.xml', + 'views/dss_ads.xml', + 'views/dss_contracts.xml', + 'views/dss_mediafiles.xml', + 'views/dss_addstructures.xml', + 'views/dss_texts.xml', 'views/mainsystem_view.xml', 'views/company_view.xml', ], diff --git a/models/__pycache__/dss.cpython-311.pyc b/models/__pycache__/dss.cpython-311.pyc index e5951ed9b1055260cef6149df5d534848b69c509..2249ac00766507c665ae8f7bb98b53aaba194584 100644 GIT binary patch literal 66214 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

5E+H5Fl2+qRC7rr9&0JAdVBxLVW&Vb~Sq))C_ zzujQNBfYY@4B>lrSFxm7He)Qyz^Jo*3wmJnYfZM+A*aFS{5Nwe@2#>iyA8I~TwDvv z*J`VYuq{_@8Mz|;wa28tUd>h9Yqx!CIm20@QBkhLDoYt|V)3T>w#7HI_-g(AHL*P8 zb*(M0H_13?Lg#r6W9!3k=5-%KzbRN zDpQ#ZK`l8@zyXC|cy^+-_%2GK8Q{O3Qg>69GfLe{r6vjGOG*uGBz9QsrLymTaoN9# z=+C~zujM3RHTEf5zK?R9z2y&69Xz+?Y4@zs^82au1A6Jfedrfrl;!$Q;pQiDtV#td zUy;4f+xshwkVr+OUM7VrLJYHuYf$Bq=M;=DeH0jKQj-}F#uUTL#mLRWvE&>X@{IB^ z{KzH5)~gRK1+ptSORD81B+HZ5RCb{TqE~q$U9yvK`QsS2El%}x+)L4^B1^8@_3^SL1$5eEBgp2MPrjC_;&F0^yoHIh3PS9wx z)1O&BVVO{>OL>%*h)}oSPod1@hTfqnF;3$)O{bk@%lbKLydW@cI39A3dn1o}BVun< z>W$t|=p($tpF`{{*&`XdJy=O(pQ&uruRhnJv5xy%MSH_kw4ulQ-gva{4RPO_(!Mv< zqOrX$Mw#dXvPUx>Nw5VrDGzYg^m!Cs_QRv$=w#$lJQ;^C^LXkiKZ;=TQ_6ox@k(vP z6Ff}4>BMnZi#z+f4-CwbS(W~oFgFXoqv8Hptjh`G5Mj`SYR5Pbe(J|~_iGyio0#4Yjv zoWM;2ze|8Pr?fW;Gc@8pkW1#!5U8~USV@EJqKf-rWWj12ujK9dGbKXEDML< zquL_{O4c6CDBnEQ8x3=^`wZT^Fn?9@Ha_-tJo0wjuX~Vu*!kN#rS3st?U1nMgy=mf zc~1&whDGl%Y^Z&~`3+yca`VcZk5#U!>(;enmf=7}XO;b1fEF{qdsZ_)qbtGSj|P!? zEz;W=*R?$BdJ$_W6Tivjn$~kBp4CW(PW4N9jAxjX=?_Lutl!9N;Oj87Gh}w3EZ?tC z)>p`zt^6)i`E}*1UO?QiV}P9~wLXBy@;IDh$Q6&_g<$47pLu#aixh(&{OgrRN*w+}N;SZhLdCbQ4GIZTdy2^_IVuhm?#bQ+;sm z+qR7gFu?o-{qp8%7!O`~`I~m_7QRNCA=E2H2IT5x*K=8W=?~?Y`*o^OdkY5ex+crI z`m?@&%@HBCj9u59c+wsm%wEYiz|WyCu$f&kL}C<+CiG`H%}ks6Eaw^~tba*Z6gPy2 zZ|M(Yn?Q4bj2~t>!!yGg(!!=gin(F9J=`5ljK*+UO1Lqd=mCq7NJdlX@MJWR2q%aa z4Ugm4ozV-)*iyAKeVpNV0*CnUVU4!{;$HIO6{gb? z!`SJWgvAw(P#TZny>KHG$s%Qz7PKalD>hqgqA)gjG0pM61)iKgn_!#xeuiFRd;Zue zm62!~d3-(red5NBR1_zI^=JyYOX1WaBH;Wt=OCxV1&7?SOLSacI+{(546F5A%Mf`@?+cz4 z42?;lvALe5vMQ-;WwyjLt4Uaec1TqlM0cm;?iAdeOO>^^3x&pwQst({mEDgjyB`h; z2Zx2TZwQf?6qykECWWaP>{5R#=K%T7@5?<;Kl^gtAhWWn2-%YX&h;(%Di^xmd3)~d zC12>~6`^vqwM(v6gKbwFz>_OKk64YofbBp5q-mwZ}_n<`p6d*eWQ|ZRPc>1 z)rN2P<8*faDhB2^F4Z>PJ~F>at%9{uXx-z`mPes2566BxE)2gZO!Lz8EHZKc2ht-8 z2XY4~Tib?Ih`g1u!({*w4){^1`rRGh+_9K1hE__Ul>+ zAC)(KCyF;)&QLj54%0^fabIzk?g0@SIGg)XedBjlyx00OtKVBK)~}K3*UXhlMKwze z%jvgPVE;3DB_g|Q`o4pk*XNbYoKoDz9c7=`Iorg3J%@uLjB_dH)|=Dgip*r6I4w+I z#kY&VQI!nv{~FJ-+c-=ai=E#=5dS|C_@4+cp6lPz-2#E1Bp?E)j2Hjw6u`#uZ_wQz z5O@e+X0+tWi&t@O0F={MM8_^;U4`Xk3cBcIdZlgjJr9v2?a3t41s@hDyHzPvuY)h8 z$AR6C0=pm93&&1K$4(1-&WM3wDKPvvF!m@gh6cTmbBNkFc$nH4a4!F8xudRgDcrmi zZd(esEY&qH)rXhr8gHLkYFc%t^j^)+M3(9ro`#D30T^&HP!xDUd;bw~^yRd-xmB;B z?TJT4A8=`XfVI2MZm@R8W?Z~Ql$Kq_T7+0OOyq^=6CR~c@P7tUYnR4#pbaBvFSK7$ zX~?nJsVV+_q$cNM))|Q=jP8=I{>rj(erEP!WaR3yZD*J1OX_9kuPYuzZjWGYVbc`O zm*c|<(@s+%c7r{_5C15kru zSGgJLiP5PklqF*cV2%E5>Uy-af6cBpz`EWM*7c5{>n$}lNsSxk^5@EHscgYUSPp{u4U#7Q#6h9x` zEKlKZ86S-rQ7+EROA;B(xXhi^=ynLzJE#$gjVq>3N*x!^=#9$76(ARdxAU#s*!5iE z$)PWHkv<=stAX#u6EOtrGCDsS5YX#0LKqlO1UA11B(|#L*U%l2J~^+eC&K?W(rd{# zc8DmQ>wh7nKO{h8fYDMD;WTKbfY@~N*;UKp+_KfncH)oLoA7*fHW9n53Aa1q-1%iK z=M~yoq;zY>Nio{WxFyz^f1f_Z`ZoLgZ{iW0BV&*L6!&t8Da|A`hRy{QQMX2HluMJv zqQHV7O0gwBJ)vExG72C-~VqW>r7ikEy< z*iur2{l4W3jqlKQ#PaG}7Z$EclP*FGv=`+$3YTG}-roQ+6l$EC9q!lkc(GGEW> zqJeQ8YzPSSWrZ6#k$Z*$PvoAX*?2s6ntrb4cGJ0J>-VXU=ImZNC=PJ0Lg6He6 zIbN_)OCL4%=|6|9C)k>zV1Pe}{PIT#u;l~^K$NaZzMQdKF!*n_+lhrLokPw`!Q9@- z9MM^Ng%4Iynxi~&IhU@t^$lCR(}^BJVsZ2kVhtBcu($iMukDeq?N0nb-h*zTeUGrZ z>%)NHYZHC_lCOWxxl{sk?3|*_OU2%Aw7%0iKfTx^t>_fWHj2fYq~cA2_Wx-fkQgSL za$CCWMqhiVz`X@z)EqaN|y9ZN^*#KO~Et`J}VB- zXQ>(fs`_&MSYu8_A`pQ88bX_uJw;|=r+<=@l%JXa9xzXpo+I~G>#q6i&$RSSQotNf|M0(4t{3Uxa? z!-K>&e%Z>UVsNu;oqq zAB>8@s1%Hvkk^W(>!i|kHx57XRKn@i*@cGtogY>U=c9sWMD&bEo)Mg|=~1kW(UBS= zM9|Fet=z9r(7wDrqHf-Ud7y59pl*P4I;V14=uTnXApMWc2v_0X{B6rCmZ>c z{UTqzKlI@?A%dkBC;B+a#~CJn%{zqPPBHlZwRSx{O+-O_x3Ex(EoJStwRoVVEd?sz zA2gIAVwFH5hESphYmAXnMFcEZH5$_+2M;~egoB5E3_b$Kx5*whJ#p{@w8~{D4X66-f-f%p2hjFUbA{ z#Se8SJ*qEMDwIEwiMzy?l6@(~mx5ZPOjt?EzG=lb4HY&SpQhr3bkgpmzW#Ap^#)5@ z<=139LA-OacTVxn6(8#5UH`KK4d=r*WIy~;p8?O$q;Tm``5A#*z%MvbDI-f6Mam#q zN7u}rjGt~2Da|gv;9DSa9Q{5)qW3@?NXvn=5=di-*>lQW*&7TRh_XVk*24><_?Hen zHo;%xnqcR8L}cd>F(eB>qZz5$JVLm}0pLj)Zc5@lJZqb9EhxaRrzR}%L#S>-qDz1v ze;&~2PXo)?WVH((0#&=W5B7GewtSX`@oMkRUM>fWV#e&l_cWN(_02wI0XwqK4?e!n z!t41$9y5eid-pI!B=Cg0VL^ya4x`rvyyCMbPk4t|9YFPD_QQ+pK3zzix6_XCQPklp zSagk#r>cFq>><3Ng(?{A;&c`Jh@eJT1yb=&K8Au@7@%Jw{6P4LV8dvMr3GoRG+Gjg zmQta$6lgYen#P!BHl@k`Xrih-J_@A#3A%=u&Pv`)Ui)QFvO3DQ^S{9u{ug)f4F(98 zQ=YH&aD0E!flcN5i?pd+Uy-&JiK|GP$~lX)soWrGY$`WUq|GdBcB1cl#*LDHZ7Sy_ z=1t`$h!IC%{aQ{6lqWbLtZvz)9`oz`lx zW{=}ORyf-Fx>HBFW+*rLWu8y*HLmjqgb&z_>NT_3hHaRKTOcdIIiIPcTr-qQybDKV z1qg-lI?6ReIXr{5Rw#MPm+L6k4CO9AfW}sUNP3};a?MbNtY&oAwzh8U*9y#GkZXoA zY8@9HD^PhJSO(X@2ljoM{f&0ArTv<1LxbqA6`(FOOd7~FL)pn+;Awug_-ma4IxVc< zzve+iAFROU0pyyYjIHr___Rm%g`iGrwb-{X7$_r{MT^d>MeR>sB*CypfbCNVO(%oRJNLRS2_lAmK_vKw$ozupwNY`u()eL%*> zx#EXX$x23_s-`#v;FMup8pXu}E+LH5P+TJ5lES!jic#phH+YoQv)t7 zjMGt^25{+NoSxz`0H+P(3>2pWoIZ>*Qk(&B#xTxAaVEf-LpY_GWwy#37V?{z9Cd1s zb9j(-`UXAjwH)W+2(w)$KNU~r6rG6!Os@*2E_o=0Onf7c>{Y7cQrN_qRFc+{t_N&r z0$DX+)1H&Vq{_*((&*5z=`$J9bBLxFCIuvAgq~R~@aV|3p7a=$|IQmmqK{XTq2uaC z7%ot1!juNq2(+f>Vn9Az(ytdLV39mCYnjO;N8_!e`h;2w!(JrA%Gze^IS-`gM@Y}2{3*nK(imsOd$QuBnLLyL8lF^>?mG%Hancl*OO_)J*$}*+PBIoZM(|Zp zzGWfp24rm0btXvvF7P%7@6{@!KX@Oa?X8U%SxbcMI@&(J5F`2PY5Ve!Ja$C{f5YN- zKf5x5pm8w)+Zxf{6w$saqP>~6&#z@GyEPq?y_*&h>{vvA?VA_1?~H2SvZ#GmRQp!87u49s z?gqG>-2*{jZ$QO*y$3w*TW@Q=&ZGuny{_T@fE;k(&1Hm9RFS7M>X}sXcE(BhUt}b$ z#7I{D^a7FV>`k~112J8$F)kJEI5mJ5;y835oE||k0$loBIsyX#D%ED=%%o4(5T`{9 zxvE>kWCjI4Qeg$0V}X=F+yT$9hof==v4ie@PlTXX^y}hGK|u~uZZHRhH3c4H9ONH{ ztX!%mQ!%e4mjm<>Vw#N&3hdk4PM*@~$)vG1E)yQd$&ZZfXo=^hK-{34bsZ(ISYC-?fb&%5 zewt%2=U3N5+11Pt`EK@DEE_KN_P^)=Ovrwls<~V}*>I_8 zvPnp_iK#X|-bP19PP01liep*YDU`Ud2lA1lf_Z^d6zL_yNQ4EtfV`rD`+OAj)uMXi z3}C&ug=vQutIr-ge~gbeaGB&!MTe?aK|>%8Z13V640jfuU`>Qw5I7QPeZT@6aCx~d zXy?w73&q(AG!M6$e6zTKd6E3QxQfZVl~!V4)*){|b!5!^?Vu|QHEc%Hta zBg3#jsHI?AO0r?)K=K@3d&r+nrc1NQrP4~~C33rTFSWxB1NSiYc?rQJfG`K?tX`S) zI-(y(fWGiXq9d-0yMT|6kj|P${YAW8g7s=mr~Jn<@@~zZpt1MYevY|7ep|c2PG{j! zF!iUY%g;GH=3)_e6oW8#&oJf2~f(@k2N z{_0Nzk+3+yn|ZlG6cg`pA2{fA54gDdQS>nc#}VKPh2X>L4H1CKzVqKvu6Vl4Ww6ci}v&oh-J?HzT z_VQJS`D9K==EP)fV%@CTd{Hr(G_^rc7l`TtGPEMkuihf4w}|R36YX>6{HfY2jeNm! z!Q3F48~9kmtc05O3+6h}T!$D#&XnRx(sZX_s1yyAe5`f}8h!S~`zMc2HwyZ4QD2Ta zM`H{HASd;CfAWjNf?>62SdF5jp-t}@db5)xn4Ba zgPL=elBso~rR4d2{OawzrAM&zh?X8c);MP>n#vbVMSStfA13prp8bNUM>Ii;elFd9 zv39bB&#n^Emx<}iCOT(Lg;V)g%6Lb!U}_OfEkHDDEP%<+;tLxEW0PoXg5KvOQ%_GpAQ z?_!Ur&71ZJ+FDUtJJB_(wZYohJ#7-SC8D-uqU)|gW+?)TweUro1oLLmyqVf3ALccM zFW4X$Iz&SU&MHuKth>_17jF?PTSd!On1)%iBZ@OU8^*t4x|y$BFQm7L>1`98a~eA= z-ty^kzF{M;=@K+uqNa%%qK3}Yb`>()?*06T}YUNXo{ zF~s?>&e9vl#=_Bn0U={eYJH{!_3n+5}` zTAWDJ(*@;F68W0PNK}ue7O^QHBQ>HxN{#48P5Vjfu@b{*MhBd~fEGz%Eiz`b5uKz{ z3iO8b$LgXe;2Z{Iz=k|-Bw~-6oI9>o;_-rVD2-eL+=s^%{&{{=6h9s|C>I=Un4>7n zlC-c67B+JxD`K3MC>rZL%@&EZHrS15;UVH#V+gxIBaa`=SNk0%%lX|p3} z@mxbWgh7D*pm@&-74IQjZ=NfEs37#j=0;T=g=`+w8xA%f>WzYc5^@VnT4|C?8aEVV zlml-diDtWpe3%4o<66nxx7*B>(7;t8s0OewOQ|7q8?<@vVpA;w3|s5CI=rn1FrFBc zW@}$VtR1@a{fJC%hj`ApU7W28Iw2c7@=Z9cc zT6Z=RM}FCT)-Of(BJL?9pGI&E!P5wyL4esEhb1=`i{L8=<`7`m=WYN9Bm@IGME-n4 zzJ*8yCPDYR0l<`?#(W%V z&s|4Aqx^s2-8%?Sb2=st6BY`72RB|Dso7$U#lTHc1{?fA4}C&Vmx$^T@X#vLnRVy8 zrkVwnLsU5?*3KrIA;#{TYI~mLla~p}%f#em5Mq;bXKK$kUi811!6(%UNws29?Zlc{ zwH5q*DsQVoN2=};)Lo*w3xw)&FZNHm`O+3%w?fdZ5Opgix@Wcai#?=qtFcAUl!}^C z$QIIU5K*ktnL=8*m{tz)U6%)Z9zMTL(AA5&dSKFJ17?^nZsm2W1l=l8w~9QyHP_D@ zP6>unqTv(<0*PySgl{~~>rM!|6Qb?}u<8pg-Y@D4o=@hRPxAUxg8r1K2l|Yl))3j$ z6{5NV)D7xk71Aojv`WxJiWz*)G9kTMOs|HR8H`(ZWwL?;^1G1N;vWhj1nO7}fdD7E z$TfE+ncHTN!on}4urR8iVF5w{1cpx?7R-!_?73+t*T*x6>bjcz?OKL1=<>-g$Bksu z^;D8@JdLaY$6Rz=O%B4}4e)nvy~2*!9R0Du1I5sD?-DMZ{0%t23Y_51wc&sP9?cZ; zXryt6InI2YVJ&b{tW8S`NnA5R!m(3~4qX+^t95o|lW)2Ppn@XxtavJTIwm3XR*VXXC}k^F9_bW)wT zOOsRteH91$D&A#OhR&wDcfr|oguEguV}2xM5$(maeSY4{*@~d#S9cj>%GpZt(_L1k ziv0I3d+9RhH+bM2n#tbsDE^ute|N8OeQiW7(cw|jp=`|OB3OkX6 z-R6YlGYvsa%6FSf8$(ZF&1)hwXV|6?4LJ_{&EcnOyG>aU1F3f{A8H7RVq3^NyX}sM zvuJi@RN!o8TOnkwA_aR|nR4RZV`V-*F21)XQ)k9V6BQRp?%t!>zXv7$Qx9Ohi@W`d z&o=1w+1z8kaX56b_22$3$890E_u3PnxNQa^ZY}xq-rqA?^0R%bz#rVQ_O&vKFJMCx z>A%m-q?0@M-C>%@4QC(Ic`IpuJ_A9r>cC&6$bAwCBO~`RvWCr0+CCo($zk?TJO)&V zWxeD#Y;HO&t7E;#yuSGo+3f0Oc9BD_)xj9n^3P+~bJ#5nWb-jB75k$xjE0>=s4AT< zpUZb_lm;uV7u)v&2*mZ{@skwQk`6k(eFt5G<8a;;NWh0f!=$v|%-p!u-hWWOB^;lvLWe1)hB; zb?G4ptUB5YK&VqJg;VRUbn=b{!O|#N8nN0i1dEb+X|wt~s1Z*=d84lt^|gF1gqy6A zss1Yv44Z|l7BLITE%R(<@l?;1eb09bnN4D56KNgJ?S|ijK$8P%!1Cuy z`TC85sY^6n=+HjJks_Y!)mnq6L&UMxw}9M{>z`zF_x5WdwB< z1a#iMjBnh*r|lHdc8X~`7sS&VzS$2^Gow`w`Tzud0HSH<6Nw&Py+cs%5Y;=dew@d9 zd9_ba`$V-5YkI5@SMbHng1JRBgIb0;^7=LldCgrbMc!lv3bGPX;CYa|{YE1Brbi9+ zQ!Yc_qsFOSX+s*a@-cH(I;#c;k`_pTgcSFaYXnxj%gvz|;L6FBQJY-GkoVqRf6r9g zcG$9x#WfsuDcct0+JVHaR5H!{T0w9i3D3XjNw#}{vjF3`vK>x$Y&8{_Jm1qdbZ~b6 zA?)fjYKTc+mm_1ztxk9OGe{M&)#)ymp^QBUFlXhQc=tbW2X7ESlRyH(zM6`fipY%f z9a#yGV#iXpc@8-d;Kuge2K>Ukn@QG=vBgq~*(9h6MO7i}<|I8NlTBw^&bMF=X@MM4 zHMJ{vc=OS%Ldk;X(1HerC-*(9mk%(c)YDJ8&uYnx$D9vuuJOQ={#f{A0LO~skbb?X zY${k)O&X4rLRc6%(sNJi{rrfr_y~?-Y3r%Bdis4w@T~!6?yWMCebjeP6Mg+?mj5Km zI}PdtO{8AZMASMJC{O)>#AL-70rT<73=8LqFw6*#V8OyrNp zbAp+p_JkFVVrx#=<7fs#cEhuc96w==)3NrMY$EK)Dq?kP&P*`<3!7Cc+rx<|(BuNS zb!V0WZu8(a>7^)_rV?Tc?rLH_`4OXxfum&pwiDA#;<^CNP#23LR z99Hz4Q2$lA_N&E^lDSDCxWBj%ogUrvDo#?KCPXIkn2quw$rG!`ga2U0LAXuny<; zV>bs7P>1cpyM6$9+yLGlM1UC(H;8vb2&lUq#=8;n;pcx=_bN713q%y-?_k5cXS|9m z2u{Q0oh0f9={EfSrX}d+}W)?ACO>Itbr4FeC+t$GdBUUF?gAPc{Sl$O}9K_f_r@trrk zL%XMqzxBmj|LZ9FH1bF`)_evV+mW5dtbDw~n8jU0x%W24OF)vuA^bL6-lxd5w=&47 z^9po~-=AEirXgy&lvh;{F8TkE4aAy>e`>r|`>)Bn zlGd7cV*ynse%mq%T|?d*bZVbypZwq{n?DhI_&?grj+UY!rWo%&&5kMI-U1_0@Bv!u zrKPM@KkwIC$xo*DNY;9bT1(!lZb)Pg*5KsaF29<4CrnQ z!!UEQM56n!h?yf3AKLu9tYB7F%rE{wmuNmyASRlp+JwYBF)?pKc{g@j45Pa%TN=VE z_NMn}+xrVCIE4dwqQRN|^TY2U{{5u+)_tV+qn45s#(q~84d5ezJ?|m@{rSdR@-H9l jGDp)=e)wKMb@^4M@Nx~4!Q@`P&fH9qrJ-y9bf*3nsdWw! diff --git a/models/dss.py b/models/dss.py index 1e643bb..375e79b 100755 --- a/models/dss.py +++ b/models/dss.py @@ -1,15 +1,33 @@ # -*- coding: utf-8 -*- + import ast import json import re import uuid import logging +import base64 +import subprocess +import tempfile +import easywebdav +import os +import os.path from odoo import api, fields, models, _ +from odoo import tools from odoo.exceptions import ValidationError +from datetime import date _logger = logging.getLogger(__name__) +def _generate_preview_from_binary(self, videofile_file): + cmd = ['ffmpeg', '-i','-','-ss','00:00:01','-vframes','1','-f','image2','-'] + p = subprocess.Popen(cmd,stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out,err = p.communicate(videofile_file) + if p.returncode != 0: + pass + + return base64.b64encode(out) + class dsscontracts(models.Model): @api.model @@ -39,69 +57,94 @@ class dsscontracts(models.Model): _name = "dss.contracts" _description = "DigitalSignage Vertraege" _rec_name = "contract_auto_name" - _inherit = ['mail.thread'] + _inherit = ['mail.thread','mail.activity.mixin'] uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') - contract_id = fields.Char("Kundennummer",store=True) - contract_name = fields.Char('Kurzbezeichnung', required=True) - contract_state = fields.Many2one('dss.contractstate',group_expand='_read_group_stage_ids') + contract_id = fields.Char("Kundennummer",store=True,tracking=True) + contract_name = fields.Char('Kurzbezeichnung', required=True,tracking=True) + contract_state = fields.Many2one('dss.contractstate',group_expand='_read_group_stage_ids',tracking=True) contract_state_order = fields.Integer(related='contract_state.order',store=True) - contract_auto_id = fields.Char("Kundennummer") - contract_auto_name = fields.Char('Vertragskennug') - project = fields.Many2one('dss.projects' , string='Project', store=True) + contract_auto_id = fields.Char("Kundennummer",tracking=True) + contract_auto_name = fields.Char('Vertragskennug',tracking=True) + project = fields.Many2one('dss.projects' , string='Project', store=True,tracking=True) project_id = fields.Integer(related='project.projectid', string='Project ID') - projectIid = fields.Integer('Project IID') - client = fields.Many2one('res.partner',domain="['&',('dsspartner','=',True),('dsspartner_werbung','=',True)]") - client_id = fields.Char("Kundenid") + projectIid = fields.Integer('Project IID',tracking=True) + client = fields.Many2one('res.partner',domain="['&',('dsspartner','=',True),('dsspartner_werbung','=',True)]",tracking=True) + client_id = fields.Char("Kundenid",tracking=True) client_uuid = fields.Char(related="client.dss_uuid") - parent_id = fields.Many2one('dss.contracts', string='Parent Task', index=True) + parent_id = fields.Many2one('dss.contracts', string='Parent Task', index=True,tracking=True) - client_short_company = fields.Char('Firmenname Kunde') - client_short_vorname = fields.Char('Vorname Kunde') - client_short_name = fields.Char('Name Kunde') - client_short_strasse = fields.Char('Strasse Kunde') - client_short_plz = fields.Char('PLZ Kunde') - client_short_ort = fields.Char('Ort Kunde') - client_short_land = fields.Many2one('res.country','Land Kunde') - client_short_email = fields.Char('Email Kunde') - client_short_telefon = fields.Char('Telefon Kunde') - client_short_mobil = fields.Char('Mobilfunk Kunde') - client_short_website = fields.Char('Webseite Kunde') + client_short_company = fields.Char('Firmenname Kunde',tracking=True) + client_short_vorname = fields.Char('Vorname Kunde',tracking=True) + client_short_name = fields.Char('Name Kunde',tracking=True) + client_short_strasse = fields.Char('Strasse Kunde',tracking=True) + client_short_plz = fields.Char('PLZ Kunde',tracking=True) + client_short_ort = fields.Char('Ort Kunde',tracking=True) + client_short_land = fields.Many2one('res.country','Land Kunde',tracking=True) + client_short_email = fields.Char('Email Kunde',tracking=True) + client_short_telefon = fields.Char('Telefon Kunde',tracking=True) + client_short_mobil = fields.Char('Mobilfunk Kunde',tracking=True) + client_short_website = fields.Char('Webseite Kunde',tracking=True) - client_other_projects = fields.Many2many('dss.projects',string='Weitere Projekte') + client_other_projects = fields.Many2many('dss.projects',string='Weitere Projekte',tracking=True) - werbe_feld_selected = fields.Many2many('dss.advertisefields',string='Werbefelder') + werbe_feld_selected = fields.Many2many('dss.advertisefields',string='Werbefelder',tracking=True) - main_runtime = fields.Integer('Gesamtlaufzeit') - split_runtime_count = fields.Integer('Laufzeit Teilungen') - split_runtime_time = fields.Integer('Laufzeit Sekunden') + main_runtime = fields.Integer('Gesamtlaufzeit',tracking=True) + split_runtime_count = fields.Integer('Laufzeit Teilungen',tracking=True) + split_runtime_time = fields.Integer('Laufzeit Sekunden',tracking=True) - contract_date = fields.Date('Vertragsdatum') - start_date = fields.Date('Ausstrahlungsdatum') + contract_date = fields.Date('Vertragsdatum',tracking=True) + start_date = fields.Date('Ausstrahlungsdatum',tracking=True) - runtimesystem = fields.Selection([('M','Monatslaufzeit'),('T','Tagelaufzeit'), ('E','Eventlaufzeit'), ('S','Sonderlaufzeit')]) - runtime_m = fields.Integer('Laufzeit') - runtime_t = fields.Integer('Laufzeit') - runtime_events = fields.Many2many('dss.eventdays') - runtime_divers = fields.Char('Laufzeit') + runtimesystem = fields.Selection([('M','Monatslaufzeit'),('T','Tagelaufzeit'), ('E','Eventlaufzeit'), ('S','Sonderlaufzeit')],tracking=True) + runtime_m = fields.Integer('Laufzeit',tracking=True) + runtime_t = fields.Integer('Laufzeit',tracking=True) + runtime_events = fields.Many2many('dss.eventdays',tracking=True) + runtime_divers = fields.Char('Laufzeit',tracking=True) - - info_account_changes = fields.Boolean('Benarichtigen bei Accountänderungen') - info_spot_changes = fields.Boolean('Benarichtigen bei Spotänderungen') - info_contract_changes = fields.Boolean('Benarichtigen bei Vertragsänderungen') - info_partner_changes = fields.Boolean('Benarichtigen bei Partneränderungen') - info_partner = fields.Many2one('res.partner','Benarichtigung an : ') + paymentsystems = fields.Many2one('dss.paysystems',tracking=True) + intern_info_payment_off = fields.Boolean('Keine Zahl-Benachrichtigungen',tracking=True) - work_state = fields.Many2one('dss.workstate',default=_default_work_state) + base_ad = fields.Many2one('dss.ads',tracking=True) + ads = fields.One2many('dss.ads','contract',tracking=True) + + vnnox_zugang_erstellt = fields.Boolean('Vnnox Zugang ?',tracking=True) + vnnox_zugang_username = fields.Char('Vnnox Username',tracking=True) + vnnox_zugang_password = fields.Char('Vnnox Passwort',tracking=True) + vnnox_zugang_gesendet = fields.Boolean('Vnnox Zugang gesendet?',tracking=True) + + xibo_zugang_erstellt = fields.Boolean('Xibo Zugang ?',tracking=True) + xibo_zugang_username = fields.Char('Xibo Username',tracking=True) + xibo_zugang_password = fields.Char('Xibo Passwort',tracking=True) + vnnox_zugang_gesendet = fields.Boolean('Xibo Zugang gesendet?',tracking=True) + + lmw_zugang_erstellt = fields.Boolean('LMW Zugang ?',tracking=True) + lmw_zugang_username = fields.Char('LMW Username',tracking=True) + lmw_zugang_password = fields.Char('LMW Passwort',tracking=True) + lmw_zugang_gesendet = fields.Boolean('LMW Zugang gesendet?',tracking=True) + + wflow_korrekturabzug = fields.Boolean('Korekturabzug gesendet ?',tracking=True) + wflow_ausstahlung = fields.Boolean('Eingespielt/Ausgestahlt ?',tracking=True) + wflow_aenderung = fields.Boolean('Änderung durchgeführt ?',tracking=True) + + info_account_changes = fields.Boolean('Benachrichtigen bei Accountänderungen',tracking=True) + info_spot_changes = fields.Boolean('Benachrichtigen bei Spotänderungen',tracking=True) + info_contract_changes = fields.Boolean('Benachrichtigen bei Vertragsänderungen',tracking=True) + info_partner_changes = fields.Boolean('Benachrichtigen bei Partneränderungen',tracking=True) + info_partner = fields.Many2one('res.partner','Benachrichtigung an : ',tracking=True) + + work_state = fields.Many2one('dss.workstate',default=_default_work_state,tracking=True) work_state_color = fields.Char(related='work_state.color') work_state_text = fields.Char(related='work_state.statusname') - work_state_info = fields.Char('Zusatzinfo') + work_state_info = fields.Char('Zusatzinfo',tracking=True) - todo_state = fields.Many2one('dss.todostate',default=_default_todo_state) + todo_state = fields.Many2one('dss.todostate',default=_default_todo_state,tracking=True) todo_state_color = fields.Char(related='todo_state.color') todo_state_text = fields.Char(related='todo_state.statusname') - todo_state_info = fields.Char('Zusatzinfo') - todo_state_until = fields.Date('Abarbeiten bis') + todo_state_info = fields.Char('Zusatzinfo',tracking=True) + todo_state_until = fields.Date('Abarbeiten bis',tracking=True) + cloud_contract_directory = fields.Char('Cloud Kunden Ordner',tracking=True) @api.constrains('client_id') def _check_client_id(self) : @@ -192,6 +235,28 @@ class dsscontracts(models.Model): # action['context'] = context return action + def tokampagne(self): + action = self.env['ir.actions.act_window'].with_context({'default_contractid': self.id})._for_xml_id('DigitalSignage.action_dss_ads_view') + context = action['context'] + kampagne=self.env['dss.ads'].search([('contract','=',self.id)],limit=1) + if not kampagne : + defadstate = self.env['dss.adstate'].search([('default','=',True)],limit=1).id + if not defadstate : + defadstate == 1 + kampagne = self.env['dss.ads'].create({'contract': self.id, 'project': self.project.id, 'adname': 'WK '+self.contract_auto_name,'adtype':'MAIN','ad_state':defadstate}) + kampagne.parent_ad = kampagne.id + return { + 'type': 'ir.actions.act_window', + 'view_type':'form', + 'view_mode':'form,tree', + 'res_model':'dss.ads', + 'target':'current', + 'context':'', + 'res_id':kampagne.id, + 'display_name' : 'Änderung zur Werbekampagne '+kampagne.parent_ad.adname, + 'domain':'[("id","=","context[kampagne.id]")]' + } + @api.model def pyaction_view_contract(self): @@ -231,28 +296,31 @@ class dssmain(models.Model): _name = "dss.projects" _description = "DigitalSignage Projekte" _rec_name = "projektname" - _inherit = ['mail.thread'] + _inherit = ['mail.thread','mail.activity.mixin'] projektname = fields.Char('Projektname', required=True) uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') - projectid = fields.Integer('Projekt ID') - color = fields.Integer('Color Index') - active = fields.Boolean('Active', default=True) - name = fields.Char('Interner Name', required=True) - aktstatus = fields.Many2one('dss.projectstate',string='Aktueller Status:') - aktstatus_color = fields.Integer(related='aktstatus.color') + projectid = fields.Integer('Projekt ID',tracking=True) + color = fields.Char('Color Index',tracking=True) + active = fields.Boolean('Active', default=True,tracking=True) + name = fields.Char('Interner Name', required=True,tracking=True) + aktstatus = fields.Many2one('dss.projectstate',string='Aktueller Status:',tracking=True) + aktstatus_typ = fields.Selection(related='aktstatus.typ') + aktstatus_color = fields.Char(related='aktstatus.color') aktstatus_icon = fields.Image(related='aktstatus.icon') - description = fields.Text('Beschreibung') - systemname = fields.Many2one('dss.systems') - grundsystemname = fields.Many2one('dss.systemtypen') - grundsystemicon = fields.Image(related='grundsystemname.icon') + description = fields.Text('Beschreibung',tracking=True) + systemname = fields.Many2one('dss.systems',tracking=True) + grundsystemname = fields.Many2one('dss.systemtypen',tracking=True) + grundsystemicon = fields.Image(related='grundsystemname.icon',tracking=True) grundsystemicon5050 = fields.Image(related='grundsystemname.icon_5050') - vertragsschreiber = fields.Many2one('res.partner',domain="['&',('dsspartner','=',True),('dsspartner_vertrieb','=',True)]") - standortpartner = fields.Many2one('res.partner',domain="['&',('dsspartner','=',True),('dsspartner_standort','=',True)]") - vertriebspartner = fields.Many2many('res.partner',domain="['&',('dsspartner','=',True),('dsspartner_vertrieb','=',True)]") - zeiten_on = fields.Datetime('Einschaltzeit') - zeiten_off = fields.Datetime('Ausschaltzeit') - errichtet_am = fields.Datetime('Errichtungstag') - standort_inout = fields.Selection([('indoor','im Gebäude'), ('outdoor','Aussenbereich'), ('semiindoor','Überdachter Aussenbereich'),('Divers','Andere Art')]); + vertragsschreiber = fields.Many2one('res.partner',domain="['&',('dsspartner','=',True),('dsspartner_vertrieb','=',True)]",tracking=True) + standortpartner = fields.Many2one('res.partner',domain="['&',('dsspartner','=',True),('dsspartner_standort','=',True)]",tracking=True) + vertriebspartner = fields.Many2many('res.partner',domain="['&',('dsspartner','=',True),('dsspartner_vertrieb','=',True)]",tracking=True) + zeiten_on = fields.Datetime('Einschaltzeit',tracking=True) + zeiten_off = fields.Datetime('Ausschaltzeit',tracking=True) + errichtet_am = fields.Datetime('Errichtungstag',tracking=True) + standort_inout = fields.Selection([('indoor','im Gebäude'), ('outdoor','Aussenbereich'), ('semiindoor','Überdachter Aussenbereich'),('Divers','Andere Art')],tracking=True); + + cloud_main_directory = fields.Char('Cloud Projekt Ordner',tracking=True) @api.model def _default_uuid(self): @@ -277,66 +345,66 @@ class dssmain(models.Model): class dssgeraetetypen(models.Model): _name = "dss.geraetetypen" _description = "DigitalSignage Geraetetypen" - _inherit = ['mail.thread'] + _inherit = ['mail.thread','mail.activity.mixin'] _rec_name = "geraetename" geraetename = fields.Char('Geraetename', required=True) uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') - geraetetyp = fields.Selection([('SYS','Systemgerät'), ('STE','Steuergerät'), ('DIV','Anderes'), ('ANZ','Anzeigegerät'), ('PLY','Abspielgerät')]) - grundsystem = fields.Many2one('dss.systemtypen', string="Gerät ist nutzbar für") - grundsystem_kennung = fields.Char(string='Kennung', related='grundsystem.kennung') + geraetetyp = fields.Selection([('SYS','Systemgerät'), ('STE','Steuergerät'), ('DIV','Anderes'), ('ANZ','Anzeigegerät'), ('PLY','Abspielgerät')],tracking=True) + grundsystem = fields.Many2one('dss.systemtypen', string="Gerät ist nutzbar für",tracking=True) + grundsystem_kennung = fields.Char(string='Kennung', related='grundsystem.kennung',tracking=True) - farbe = fields.Char('Grundfarbe') + farbe = fields.Char('Grundfarbe',tracking=True) - has_heizung = fields.Boolean('Mit Heizsystem') - has_klima = fields.Boolean('Mit Klimasystem') - has_fan = fields.Boolean('Mit Ventiltorensystem') + has_heizung = fields.Boolean('Mit Heizsystem',tracking=True) + has_klima = fields.Boolean('Mit Klimasystem',tracking=True) + has_fan = fields.Boolean('Mit Ventiltorensystem',tracking=True) - stromzaehler = fields.Many2one('dss.geraetetypen') - stromverbrauch_avg = fields.Integer('Stromverbrauch AVG in W') + stromzaehler = fields.Many2one('dss.geraetetypen',tracking=True) + stromverbrauch_avg = fields.Integer('Stromverbrauch AVG in W',tracking=True) - osvorhanden = fields.Boolean('Mit Betriebssystem') - osname = fields.Char('Betriebssystem') - ostyp = fields.Selection([('Win','Windows'), ('Lin','Linux'), ('And','Android'),('Ras','Raspberry PI'),('Non','Keines bekannt'),('Div','Anderes')]); + osvorhanden = fields.Boolean('Mit Betriebssystem',tracking=True) + osname = fields.Char('Betriebssystem',tracking=True) + ostyp = fields.Selection([('Win','Windows'), ('Lin','Linux'), ('And','Android'),('Ras','Raspberry PI'),('Non','Keines bekannt'),('Div','Anderes')],tracking=True); - lcd_ausrichtung = fields.Selection([('quer','Horizontal/Querformat'), ('hoch','Vertikal/Hochformat'),('Divers','Andere Art')],'LCD Ausrichtung'); - lcd_touch = fields.Boolean('Touchsystem') - lcd_montage = fields.Selection([('WAN','Wandmontage'), ('FUS','Standfuss rollbar'), ('FI1','Boden verankert 1 Fuss'),('FI2','Boden verankert 2 Füsse'),('FIX','Bodenverankert Blockfuss'),('XXX','Sonstige')],'Montage/Befestigung'); - lcd_montage_sonstige = fields.Char('Sonstige Montageart') - lcd_size = fields.Selection([('42','42 Zoll'), ('55','55 Zoll'), ('65','65 Zoll'),('75','75 Zoll'),('10','10.x Zoll'),('00','Sonstige')],'LCD Größe'); - lcd_size_sonstige = fields.Char('LCD Sondergröße') + lcd_ausrichtung = fields.Selection([('quer','Horizontal/Querformat'), ('hoch','Vertikal/Hochformat'),('Divers','Andere Art')],'LCD Ausrichtung',tracking=True); + lcd_touch = fields.Boolean('Touchsystem',tracking=True) + lcd_montage = fields.Selection([('WAN','Wandmontage'), ('FUS','Standfuss rollbar'), ('FI1','Boden verankert 1 Fuss'),('FI2','Boden verankert 2 Füsse'),('FIX','Bodenverankert Blockfuss'),('XXX','Sonstige')],'Montage/Befestigung',tracking=True); + lcd_montage_sonstige = fields.Char('Sonstige Montageart',tracking=True) + lcd_size = fields.Selection([('42','42 Zoll'), ('55','55 Zoll'), ('65','65 Zoll'),('75','75 Zoll'),('10','10.x Zoll'),('00','Sonstige')],'LCD Größe',tracking=True); + lcd_size_sonstige = fields.Char('LCD Sondergröße',tracking=True) - led_geraetetyp = fields.Selection([('MOD','LED Modul'),('NET','Netzgerät'), ('REC','Receiving Karte'), ('STE','Steuerkarte'),('LFT','Lüftertyp')]) - led_module_pixelpitch = fields.Float('Modulpixelpitch') - led_module_breite = fields.Integer('Modulbreite mm') - led_module_hoehe = fields.Integer('Modulhoehe mm') - led_module_pixel_breite = fields.Integer('Modulbreite px') - led_module_pixel_hoehe = fields.Integer('Modulhoehe px') + led_geraetetyp = fields.Selection([('MOD','LED Modul'),('NET','Netzgerät'), ('REC','Receiving Karte'), ('STE','Steuerkarte'),('LFT','Lüftertyp')],tracking=True) + led_module_pixelpitch = fields.Float('Modulpixelpitch',tracking=True) + led_module_breite = fields.Integer('Modulbreite mm',tracking=True) + led_module_hoehe = fields.Integer('Modulhoehe mm',tracking=True) + led_module_pixel_breite = fields.Integer('Modulbreite px',tracking=True) + led_module_pixel_hoehe = fields.Integer('Modulhoehe px',tracking=True) - led_module_system = fields.Selection([('FIX1','Fix Verschraubt'), ('MAG1','Magnetisch haltend'), ('RIG1','Imbus Veriegelt (vorn)'),('SONS','Sonstige')],'Modul Montage/Befestigung'); - led_module_system_sonstige = fields.Char('Modulbefestigung Sonstige') - led_module_kennung = fields.Char('Modulbezeichnung') - led_module_serial = fields.Char('Modulseriennummer') - led_module_vendor = fields.Many2one('res.partner','Modul Hersteller') + led_module_system = fields.Selection([('FIX1','Fix Verschraubt'), ('MAG1','Magnetisch haltend'), ('RIG1','Imbus Veriegelt (vorn)'),('SONS','Sonstige')],'Modul Montage/Befestigung',tracking=True); + led_module_system_sonstige = fields.Char('Modulbefestigung Sonstige',tracking=True) + led_module_kennung = fields.Char('Modulbezeichnung',tracking=True) + led_module_serial = fields.Char('Modulseriennummer',tracking=True) + led_module_vendor = fields.Many2one('res.partner','Modul Hersteller',tracking=True) led_receivingcard_vendor = fields.Many2one('res.partner','Receivingcard Hersteller') led_receivingcard_kennung = fields.Char('Receivingcardtyp') - led_netzteil_typ = fields.Selection([('SNT','Schaltnetzteil'), ('STN','Steckernetzteil'), ('HNT','Hutschienennetzteil'),('INT','Internes Netzteil')],'Netzteil Bauart'); - led_netzteil_vendor = fields.Many2one('res.partner','Netzteil Hersteller') - led_netzteil_kennung = fields.Char('Netzteilkennung') - led_netzteil_spannung = fields.Char('Netzteil Spannung V') - led_netzteil_leistung = fields.Char('Netzteil Leistung W') + led_netzteil_typ = fields.Selection([('SNT','Schaltnetzteil'), ('STN','Steckernetzteil'), ('HNT','Hutschienennetzteil'),('INT','Internes Netzteil')],'Netzteil Bauart',tracking=True); + led_netzteil_vendor = fields.Many2one('res.partner','Netzteil Hersteller',tracking=True) + led_netzteil_kennung = fields.Char('Netzteilkennung',tracking=True) + led_netzteil_spannung = fields.Char('Netzteil Spannung V',tracking=True) + led_netzteil_leistung = fields.Char('Netzteil Leistung W',tracking=True) - lcd_montage = fields.Selection([('WAN','Wandmontage'), ('FUS','Standfuss rollbar'), ('FI1','Boden verankert 1 Fuss'),('FI2','Boden verankert 2 Füsse'),('FIX','Bodenverankert Blockfuss'),('XXX','Sonstige')],'Montage/Befestigung'); - lcd_montage_sonstige = fields.Char('Sonstige Montageart') + lcd_montage = fields.Selection([('WAN','Wandmontage'), ('FUS','Standfuss rollbar'), ('FI1','Boden verankert 1 Fuss'),('FI2','Boden verankert 2 Füsse'),('FIX','Bodenverankert Blockfuss'),('XXX','Sonstige')],'Montage/Befestigung',tracking=True); + lcd_montage_sonstige = fields.Char('Sonstige Montageart',tracking=True) - hw_anzeige = fields.Many2one('dss.geraetetypen',domain="[('geraetetyp','=','ANZ')]") - hw_steuerung = fields.Many2one('dss.geraetetypen',domain="['&',('geraetetyp','=','STE'),('grundsystem_kennung','=','LED')]") - hw_player = fields.Many2one('dss.geraetetypen',domain="[('geraetetyp','=','PLY')]") - hw_umwelt = fields.Many2one('dss.geraetetypen',domain="['|',('geraetetyp','=','SYS'),('geraetetyp','=','DIV')]") + hw_anzeige = fields.Many2one('dss.geraetetypen',domain="[('geraetetyp','=','ANZ')]",tracking=True) + hw_steuerung = fields.Many2one('dss.geraetetypen',domain="['&',('geraetetyp','=','STE'),('grundsystem_kennung','=','LED')]",tracking=True) + hw_player = fields.Many2one('dss.geraetetypen',domain="[('geraetetyp','=','PLY')]",tracking=True) + hw_umwelt = fields.Many2one('dss.geraetetypen',domain="['|',('geraetetyp','=','SYS'),('geraetetyp','=','DIV')]",tracking=True) - zusatz_integrationen = fields.Many2one('dss.geraetetypen') + zusatz_integrationen = fields.Many2one('dss.geraetetypen',tracking=True) @api.model def _default_uuid(self): @@ -349,6 +417,8 @@ class dssgeraetetypen(models.Model): syst.grundsystem_kennung = syst.grundsystem.kennung class dsssystemtypen(models.Model): + + _name = "dss.systemtypen" _inherit = ['mail.thread'] _description = "DigitalSignage Systemtypen" @@ -356,20 +426,35 @@ class dsssystemtypen(models.Model): uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') systemname = fields.Char('Systemname', required=True) kennung = fields.Char('Kurzkennung', required=True) - farbe = fields.Integer('Grundfarbe') + farbe = fields.Char('Grundfarbe') icon = fields.Image() - icon_5050 = fields.Image("Icon 50") - + icon_5050 = fields.Image("Icon 50",compute='_compute_icon_5050') + default_adstructure = fields.Many2one('dss.adstructures',String='Standard-Werbeaufbau') @api.model def _default_uuid(self): return str(uuid.uuid4()) + @api.depends('icon') + def _compute_icon_5050(self): + for rec in self: + if rec.icon != False: + _logger.info('compute 50x50 icon for '+rec.uuid) +# rec.mediafile_preview = self._generate_preview_from_binary(base64.decodebytes(rec.mediafile)) +# rec.icon_5050 = tools.image_resize_image(rec.icon,size=(50,50),avoid_if_small=True) + rec.icon_5050 = rec.icon +# if rec.mediafile != False: +# rec.mediafile_preview = self._generate_preview_from_binary(base64.decodebytes(rec.mediafile)) +# rec.mediafile_preview = None + else: + _logger.info('alternative compute '+rec.uuid) + rec.icon_5050 = rec.icon + return class dsssoftware(models.Model): _name = "dss.software" _description = "Softwaresysteme" - _inherit = ['mail.thread'] + _inherit = ['mail.thread','mail.activity.mixin'] _rec_name = "softwarename" # _inherit = ['mail.thread', 'mail.activity.mixin'] uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') @@ -385,7 +470,7 @@ class dsssoftware(models.Model): class dsssystems(models.Model): _name = "dss.systems" _description = "DigitalSignage Systemtypen" - _inherit = ['mail.thread'] + _inherit = ['mail.thread','mail.activity.mixin'] _rec_name = "systemname" # _inherit = ['mail.thread', 'mail.activity.mixin'] uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') @@ -440,13 +525,14 @@ class dsssystems(models.Model): class dsspprojektstatus(models.Model): _name = "dss.projectstate" _description = "DigitalSignage Projektstatus" - _inherit = ['mail.thread'] + _inherit = ['mail.thread','mail.activity.mixin'] _rec_name = "statusname" # _inherit = ['mail.thread', 'mail.activity.mixin'] uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') # uuid = fields.Char('UUID', required=True, translate=True) statusname = fields.Char('Statusname', required=True) - color = fields.Integer(string='Color Index') + color = fields.Char(string='Color Index') + typ = fields.Selection([('NEU','In Bearbeitung'),('WORK','fertig/laufend'),('ERROR','Fehlerhaft/Defekt'),('ARCHIV','veraltet/archiviert')],'Systemzuordnung') icon = fields.Image() @api.model @@ -456,13 +542,31 @@ class dsspprojektstatus(models.Model): class dsscontractstatus(models.Model): _name = "dss.contractstate" _description = "DigitalSignage Vertragsstatus" - _inherit = ['mail.thread'] + _inherit = ['mail.thread','mail.activity.mixin'] _rec_name = "statusname" # _inherit = ['mail.thread', 'mail.activity.mixin'] uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') # uuid = fields.Char('UUID', required=True, translate=True) statusname = fields.Char('Statusname', required=True) - color = fields.Integer(string='Color Index') + color = fields.Char(string='Color Index') + icon = fields.Image() + order = fields.Integer('Reihenfolge') + + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) + +class dssadstatus(models.Model): + _name = "dss.adstate" + _description = "DigitalSignage Werbeaktions-Status" + _inherit = ['mail.thread','mail.activity.mixin'] + _rec_name = "statusname" +# _inherit = ['mail.thread', 'mail.activity.mixin'] + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') +# uuid = fields.Char('UUID', required=True, translate=True) + statusname = fields.Char('Statusname', required=True) + color = fields.Char(string='Color Index') + default = fields.Boolean('Standardwert ?') icon = fields.Image() order = fields.Integer('Reihenfolge') @@ -474,7 +578,7 @@ class dsscontractstatus(models.Model): class dssworkstatus(models.Model): _name = "dss.workstate" _description = "DigitalSignage Bearbeitungsstatus" - _inherit = ['mail.thread'] + _inherit = ['mail.thread','mail.activity.mixin'] _rec_name = "statusname" # _inherit = ['mail.thread', 'mail.activity.mixin'] uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') @@ -490,7 +594,7 @@ class dssworkstatus(models.Model): class dsseventdays(models.Model): _name = "dss.eventdays" _description = "DigitalSignage EventSpieltage" - _inherit = ['mail.thread'] + _inherit = ['mail.thread','mail.activity.mixin'] _rec_name = "eventname" # _inherit = ['mail.thread', 'mail.activity.mixin'] uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') @@ -509,7 +613,7 @@ class dsseventdays(models.Model): class dsstodostatus(models.Model): _name = "dss.todostate" _description = "DigitalSignage Bearbeitungsschritte" - _inherit = ['mail.thread'] + _inherit = ['mail.thread','mail.activity.mixin'] _rec_name = "statusname" # _inherit = ['mail.thread', 'mail.activity.mixin'] uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') @@ -526,7 +630,7 @@ class dsstodostatus(models.Model): class dssadvertisefields(models.Model): _name = "dss.advertisefields" _description = "DigitalSignage Werbefelder" - _inherit = ['mail.thread'] + _inherit = ['mail.thread','mail.activity.mixin'] _rec_name = "feldname" # _inherit = ['mail.thread', 'mail.activity.mixin'] uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') @@ -542,5 +646,386 @@ class dssadvertisefields(models.Model): def _default_uuid(self): return str(uuid.uuid4()) +class dsstexts(models.Model): + _name = "dss.texts" + _description = "DigitalSignage Standard texte" + _inherit = ['mail.thread','mail.activity.mixin'] + _rec_name = "textname" +# _inherit = ['mail.thread', 'mail.activity.mixin'] + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') +# uuid = fields.Char('UUID', required=True, translate=True) + text_id = fields.Char('Kennung', required=True) + textname = fields.Char('Textname', required=True) + description = fields.Text('Text') + + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) + +class dsspaysystemfields(models.Model): + _name = "dss.paysystem_fields" + _description = "DigitalSignage Abrechnungsarten_felder" + _inherit = ['mail.thread','mail.activity.mixin'] + _rec_name = "feldname" +# _inherit = ['mail.thread', 'mail.activity.mixin'] + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') +# uuid = fields.Char('UUID', required=True, translate=True) + feldname = fields.Char('Abrechnungs_Feldname', required=True) + payonfieldset = fields.Selection([('VE','Vertragseingang'),('KA','Korrekturabzug'),('ES','Einspielung'),('CH','Jede Änderung'),('XH','X, Änderung')]) + changecount = fields.Integer('Änderungsnummer') + description = fields.Text('EventBeschreibung') + amount = fields.Float('Kosten') + + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) +class dssmediatypes(models.Model): + _name = "dss.mediatypes" + _description = "DigitalSignage Datei-Medientypen" + _inherit = ['mail.thread','mail.activity.mixin'] + _rec_name = "medianame" +# _inherit = ['mail.thread', 'mail.activity.mixin'] + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') +# uuid = fields.Char('UUID', required=True, translate=True) + medianame = fields.Char('Medien Name', required=True) + mediatype = fields.Selection([('IMG_J','Bild'),('VID_4','MP4 Video'),('FIL_X','belieb. Datei')]) + description = fields.Text('Medien Beschreibung') + cloudlink = fields.Char('Cloud Urverzeichnis') + maxsize_kb = fields.Integer('Maximale Größe KB') + maxsize_w = fields.Integer('Maximale Pixel W') + maxsize_h = fields.Integer('Maximale Pixel H') + + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) + +class dssmediarelations(models.Model): + + def _generate_preview_from_binary(self, videofile_file): + cmd = ['ffmpeg', '-i','-','-ss','00:00:01','-vframes','1','-f','image2','-'] + p = subprocess.Popen(cmd,stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out,err = p.communicate(videofile_file) + if p.returncode != 0: + pass + + return base64.b64encode(out) + + def _generate_preview_and_save_from_binary(self, videofile_file, videofile_file_name:str): + cmd = ['ffmpeg', '-i','-','-ss','00:00:01','-vframes','1','-f','image2','-'] + p = subprocess.Popen(cmd,stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + out,err = p.communicate(videofile_file) + if p.returncode != 0: + _logger.info(videofile_file_name) + fileobj = open(videofile_file_name,"xb") + fileobj.write(out) + fileobj.close() + pass + + return base64.b64encode(out) + + + _name = "dss.mediarelations" + _description = "DigitalSignage Kampagne-Medien-Zuordnung" + _inherit = ['mail.thread','mail.activity.mixin'] + _rec_name = "relname" +# _inherit = ['mail.thread', 'mail.activity.mixin'] + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') +# uuid = fields.Char('UUID', required=True, translate=True) + kampagne = fields.Many2one('dss.ads',string='Kampagne') + mediatype = fields.Many2one('dss.mediatypes',string='Medientyp') + mediatype_type = fields.Selection(related='mediatype.mediatype',string='Medientyp') + relname = fields.Char('Relationsname') + kampagnen_uuid = fields.Char('Kampagne') + mediatype_uuid = fields.Char('Medientyp') + mediafile = fields.Binary('Datei',attachment=True) + mediafile_attachment = fields.Many2one('ir.attachment',string='Datei') + mediafile_file = fields.Char('Dateiname') + mediafile_preview = fields.Binary('Datei Vorschau',compute='_compute_media_preview') + secured_ro = fields.Boolean('Gesperrt ro') + used_ro = fields.Boolean('Benutzt ro') + + @api.onchange('mediafile') + def _onchange_mediafile(self): + restr = 'keine' + for record in self : + resstr = record.uuid + _logger.info(record.mediafile) + if record.mediafile != False : + _logger.info('Generating File '+resstr) + if os.path.isfile(record.mediafile_file) : + os.remove(record.mediafile_file) + fileobj = open(record.mediafile_file,"xb") + fileobj.write(base64.decodebytes(record.mediafile)) + fileobj.close() + _logger.info(resstr+' File generated') + _logger.info(' Projekt : '+record.kampagne.contract.project.uuid) + _logger.info(' Keine Datei ') + return + + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) + + @api.depends('mediafile_file') + def _compute_media_preview(self): + for rec in self: + if rec.mediafile != False: + _logger.info('compute image for '+rec.uuid) +# rec.mediafile_preview = self._generate_preview_from_binary(base64.decodebytes(rec.mediafile)) + rec.mediafile_preview = self._generate_preview_and_save_from_binary(base64.decodebytes(rec.mediafile),rec.mediafile_file+'_prv') +# if rec.mediafile != False: +# rec.mediafile_preview = self._generate_preview_from_binary(base64.decodebytes(rec.mediafile)) +# rec.mediafile_preview = None + else: + _logger.info('alternative compute '+rec.uuid) + rec.mediafile_preview = rec.mediafile + return + +class dssadstructures(models.Model): + _name = "dss.adstructures" + _description = "DigitalSignage Werbestrukturen" + _inherit = ['mail.thread','mail.activity.mixin'] + _rec_name = "structurename" +# _inherit = ['mail.thread', 'mail.activity.mixin'] + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') +# uuid = fields.Char('UUID', required=True, translate=True) + structurename = fields.Char('Struktur Name', required=True) + kampagnen_uuid = fields.Char('Kampagne') + description = fields.Text('Struktur Beschreibung') + medias = fields.Many2many('dss.mediatypes',string='Enthaltene Dateien') + + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) + + +class dsspaysystems(models.Model): + _name = "dss.paysystems" + _description = "DigitalSignage Abrechnungsarten" + _inherit = ['mail.thread','mail.activity.mixin'] + _rec_name = "payname" +# _inherit = ['mail.thread', 'mail.activity.mixin'] + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') +# uuid = fields.Char('UUID', required=True, translate=True) + payname = fields.Char('Abrechnungsname', required=True) + payonset = fields.Many2many('dss.paysystem_fields') + description = fields.Text('EventBeschreibung') + send_info = fields.Boolean('Informationsemail senden ?') + send_info_to = fields.Many2one('res.users') + send_info_template = fields.Many2one('mail.template') + amount = fields.Float('Kosten') + icon = fields.Image() + + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) + + +class dsscontractads(models.Model): + + + def _default_work_state(self): + ds=self.env['dss.workstate'].search([('statusname','=','Neu')],limit=1).id + _logger.debug(ds) + return ds + + def _default_work_state_color(self): + ds=self.env['dss.workstate'].search([('statusname','=','Neu')],limit=1).color + _logger.info(ds) + return ds + + def _default_todo_state(self): + ds=self.env['dss.todostate'].search([('statusnr','=','0')],limit=1).id + if not ds : ds = 1 + _logger.debug(ds) +# ds = + return ds + + @api.model + def create(self,vals): + result = super().create(vals) + self['date_create'] = date.today() + self['user_create'] = self.env.user.name + return result + + _name = "dss.ads" + _description = "DigitalSignage Werbekampagnen Phasen" + _inherit = ['mail.thread','mail.activity.mixin'] + _rec_name = "adname" +# _inherit = ['mail.thread', 'mail.activity.mixin'] + uuid = fields.Char(default=lambda self: self._default_uuid(), required=True, readonly=True, copy=False, string='UUID') + + date_create = fields.Date('Erstellungsdatum',default=lambda self: self._default_create_date()) + date_lastedit = fields.Date('Änderungsdatum') + user_create = fields.Char('Erstellungsuser',default=lambda self: self._default_create_user()) + user_lastedit = fields.Char('Änderungsuser') +# uuid = fields.Char('UUID', required=True, translate=True) + adname = fields.Char('Kampagnenname', required=True,track_visibility='onchange',tracking=True) + adtype = fields.Selection([('MAIN','Ersteinrichtung'),('KCHN','Änderung durch Kunde'),('LCHN','Änderung durch Logumedia'),('SONS','Sonstige Änderung')],track_visibility='onchange',tracking=True) + adpos = fields.Integer('Reihenfolge',default=lambda self: self._default_adpos(),track_visibility='onchange',tracking=True) + + contract = fields.Many2one('dss.contracts',store=True,track_visibility='onchange',tracking=True) + contract_id = fields.Char(related='contract.contract_id') + contract_name = fields.Char(related='contract.contract_name') + + project = fields.Many2one('dss.projects' , string='Project', store=True,track_visibility='onchange',tracking=True) + project_id = fields.Integer(related='project.projectid', string='Project ID') + + parent_ad = fields.Many2one('dss.ads' , string='UrsprungsWerbung', store=True) + parent_ad_uuid = fields.Char(related='parent_ad.uuid') + description = fields.Text('Beschreibung',track_visibility='onchange') + amount = fields.Float('Extrakosten') + order = fields.Integer('Reihenfolge') + + work_state = fields.Many2one('dss.workstate',default=_default_work_state,tracking=True) + work_state_color = fields.Char(related='work_state.color') + work_state_text = fields.Char(related='work_state.statusname') + work_state_info = fields.Char('Zusatzinfo') + + ad_state = fields.Many2one('dss.adstate',tracking=True) + ad_state_color = fields.Char(related='ad_state.color') + + todo_state = fields.Many2one('dss.todostate',default=_default_todo_state,tracking=True) + todo_state_color = fields.Char(related='todo_state.color') + todo_state_text = fields.Char(related='todo_state.statusname') + todo_state_info = fields.Char('Zusatzinfo') + todo_state_until = fields.Date('Abarbeiten bis') + + mediastructure = fields.Many2one('dss.adstructures',string='Systemaufbau',tracking=True) + mediarelations = fields.One2many('dss.mediarelations','kampagne',tracking=True) + + cloud_add_directory = fields.Char('Cloud KundenKampagnen Ordner',tracking=True) + + @api.model + def _default_uuid(self): + return str(uuid.uuid4()) + + + def _default_create_date(self): + return str(date.today()) + + def _default_create_user(self): + return str(self.env.user.name) + + def _default_adpos(self): + pos = self.env['dss.ads'].search_count([('contract_id','=',self.contract.id)]) + 1 + return str(pos) + + @api.onchange('mediastructure') + def _onchange_mediastructure_id(self): + restr = 'keine' + for record in self : + resstr = record.mediastructure.uuid + _logger.info(resstr) + mtyp = self.env['dss.adstructures'].search([("uuid","=",str(record.mediastructure.uuid))]) + resstr = mtyp.structurename + _logger.info(resstr) + _logger.info(record.mediastructure.uuid) + foundused = self.env['dss.mediarelations'].search_count(["&",('kampagnen_uuid','=',record.uuid),'|',('secured_ro','=',True),('used_ro','=',True)]) + if foundused == 0 : + self.env['dss.mediarelations'].search([('kampagnen_uuid','=',record.uuid)]).unlink() + for media in mtyp.medias : + resstr = media.medianame + self.env['dss.mediarelations'].create({'kampagne': record.id,'relname':resstr,'mediatype':media.id,'kampagnen_uuid':record.uuid}) + _logger.info(resstr) + else : + _logger.info('change - Canceled !') + raise ValidationError(_("Datensatz kann nicht gewechselt werden ! Es sind benutzt Medien in der Kampagne ! Bitte erst diese freigeben !")) + self.date_lastedit = str(date.today()) + self.mediastructure = mtyp + + def pyaction_view_ad_details(self): + action = self.env['ir.actions.act_window'].with_context({'default_adid': self.id})._for_xml_id('DigitalSignage.action_dss_ads_view') +# action['display_name'] = self.ad_name +# action['domain'] = '[["projectid","=","4"]]' +# context = action['context'].replace('', str(self.id)) +# context = ast.literal_eval(context) +# context.update({ +# 'create': self.active, +# 'active_test': self.active +# }) +# action['context'] = context + return { + 'type': 'ir.actions.act_window', + 'view_type':'form', + 'view_mode':'form,tree', + 'res_model':'dss.ads', + 'target':'current', + 'context':'', + 'res_id':self.id, + 'display_name' : ' '+self.adname, + 'domain':'' + } + + return action + + def pydoviewallads(self): + action = self.env['ir.actions.act_window'].with_context({'default_adid': self.id})._for_xml_id('DigitalSignage.act_dss_ads_view_full') + action['display_name'] = self.contract_name +# action['domain'] = '[["projectid","=","4"]]' +# context = action['context'].replace('', str(self.id)) +# context = ast.literal_eval(context) +# context.update({ +# 'create': self.active, +# 'active_test': self.active +# }) +# action['context'] = context +# return { +# 'type': 'ir.actions.act_window', +# 'view_type':'form', +# 'view_mode':'form,tree', +# 'res_model':'dss.ads', +# 'target':'current', +# 'context':'', +# 'res_id':kampagne.id, +# 'display_name' : 'Werbekampagne '+kampagne.adname, +# 'domain':'[("contract","=","context[active_id]")]' +# } +# return action + return { + 'type': 'ir.actions.act_window', + 'view_type':'kanban', + 'view_mode':'kanban', + 'res_model':'dss.ads', + 'target':'current', + 'context':'{"group_by":["parent_ad"]}', +# 'res_id':self.parent_ad, + 'display_name' : 'Übersicht für '+self.adname, + 'domain':[("contract","=",self.contract.id)] + } + + def pydonewad(self): + defadstate = self.env['dss.adstate'].search([('default','=',True)],limit=1).id + if not defadstate : + defadstate == 1 + newkampagne = self.env['dss.ads'].create({'contract': self.contract.id, 'project': self.project.id, 'adname': 'AD_'+self.adname,'parent_ad':self.id, 'adtype':'KCHN','ad_state':defadstate }) +# action = self.env['ir.actions.act_window'].with_context({'default_contractid': newkampagne.id})._for_xml_id('DigitalSignage.act_dss_ads_view_contract') +# action['display_name'] = self.contract_name +# action['domain'] = '[["projectid","=","4"]]' +# context = action['context'].replace('', str(self.id)) +# context = ast.literal_eval(context) +# context.update({ +# 'create': self.active, +# 'active_test': self.active +# }) +# action['context'] = context + return { + 'type': 'ir.actions.act_window', + 'view_type':'form', + 'view_mode':'form,tree', + 'res_model':'dss.ads', + 'target':'current', + 'context':'', + 'res_id':newkampagne.id, + 'display_name' : 'Änderung zur Werbekampagne '+newkampagne.parent_ad.adname, + 'domain':'[("id","=","context[newkampagne.id]")]' + } + + return action + + def setStandardText(self,tid): + text = self.env['dss.texts'].search([('text_id','=',tid)], limit=1) + if text: + self.write({'description':text.description}) diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv index fca5190..e0cf7c4 100755 --- a/security/ir.model.access.csv +++ b/security/ir.model.access.csv @@ -9,5 +9,13 @@ digitalsignage_dss_contractstate_group_user,access.dss.contractstate,model_dss_c digitalsignage_dss_workstate_group_user,access.dss.workstate,model_dss_workstate,base.group_user,1,1,1,1 digitalsignage_dss_todostate_group_user,access.dss.todostate,model_dss_todostate,base.group_user,1,1,1,1 digitalsignage_dss_contracts_group_user,access.dss.contracts,model_dss_contracts,base.group_user,1,1,1,1 +digitalsignage_dss_adstate_group_user,access.dss.adstate,model_dss_adstate,base.group_user,1,1,1,1 digitalsignage_dss_eventdays_group_user,access.dss.eventdays,model_dss_eventdays,base.group_user,1,1,1,1 +digitalsignage_dss_paysystems_group_user,access.dss.paysystems,model_dss_paysystems,base.group_user,1,1,1,1 +digitalsignage_dss_paysystem_fields_group_user,access.dss.paysystem_fields,model_dss_paysystem_fields,base.group_user,1,1,1,1 +digitalsignage_dss_ads_fields_group_user,access.dss.ads,model_dss_ads,base.group_user,1,1,1,1 +digitalsignage_dss_adstructures_group_user,access.dss.adstructures,model_dss_adstructures,base.group_user,1,1,1,1 +digitalsignage_dss_mediatypes_group_user,access.dss.mediatypes,model_dss_mediatypes,base.group_user,1,1,1,1 +digitalsignage_dss_texts_group_user,access.dss.texts,model_dss_texts,base.group_user,1,1,1,1 +digitalsignage_dss_mediarelations_group_user,access.dss.mediarelations,model_dss_mediarelations,base.group_user,1,1,1,1 digitalsignage_dss_advertisefields_group_user,access.dss.advertisefields,model_dss_advertisefields,base.group_user,1,1,1,1 \ No newline at end of file diff --git a/static/images/tree_r.png b/static/images/tree_r.png new file mode 100644 index 0000000000000000000000000000000000000000..dfbb5935efef73b536e59ea194e0b52c7c22c6dc GIT binary patch literal 241 zcmVPx#t4TybR9Hvtn86K$Fc1WX9+EObF=>Ky0dxU1LJ^oe@-PmZfah4^fpjd^ux8J$ zh>Z`>WTgWz?mb?`v}sdam({NKz2aioctE!lmxWlw0{(J~E)a`YegteS?6}IEr5S35 znxTJoU1sR*8G5)szQSB_-tfKFQ3J0-Ch626%KQO5Gr<{{?l`rGOmtHdow?$t2wYnJ rr{3rXm3iDax<$9>mN)_35@)plFIHPb{OWN300000NkvXXu0mjf{nBF= literal 0 HcmV?d00001 diff --git a/static/images/tree_ud.png b/static/images/tree_ud.png new file mode 100644 index 0000000000000000000000000000000000000000..ccb30fc397fdb494067bbcdb38cc5a8cbd1c7ec8 GIT binary patch literal 207 zcmeAS@N?(olHy`uVBq!ia0vp^;y~=d!3HE{Kjk$6DaPU;cPEB*=VV?2Ih~#^jv*25 zZ)aEwH7M|~PQUz0_e%7O+@r^snhl!EypQ{Md{lccEL5A$wro)ed*AlwE7zNQuZ!-! z^?KjUmJ^)e5;)?P1&WY`+xq=e|3xJma>_ zmYwm5hEWo_Jz_s!=eg`qnW!?!WzvdgSF%n&cif`6Q@zcq+vUjFZAL&xF?hQAxvX2~NfU literal 0 HcmV?d00001 diff --git a/views/.mc.menu b/views/.mc.menu new file mode 100644 index 0000000..f82ee7a --- /dev/null +++ b/views/.mc.menu @@ -0,0 +1,379 @@ +shell_patterns=0 + +############################################################################## +# %% The % character +# %f The current file (if non-local vfs, file will be copied locally and +# %f will be full path to it) +# %p The current file +# %d The current working directory +# %s "Selected files"; the tagged files if any, otherwise the current file +# %t Tagged files +# %u Tagged files (and they are untagged on return from expand_format) +# %view Runs the commands and pipes standard output to the view command +# If %view is immediately followed by '{', recognize keywords +# ascii, hex, nroff and unform +# +# If the format letter is in uppercase, it refers to the other panel +# +# With a number followed the % character you can turn quoting on (default) +# and off. For example: +# %f quote expanded macro +# %1f ditto +# %0f don't quote expanded macro +############################################################################## + ++ ! t t +@ Do something on the current file + CMD=%{Enter command} + $CMD %f + ++ t t +@ Do something on the tagged files + CMD=%{Enter command} + for i in %t ; do + $CMD "$i" + done + +0 Edit a bug report and send it to root + I=`mktemp "${MC_TMPDIR:-/tmp}/mail.XXXXXX"` || exit 1 + ${EDITOR-vi} "$I" + test -r "$I" && mail root < "$I" + rm -f "$I" + +=+ f \.1$ | f \.3$ | f \.4$ | f \.5$ | f \.6$ | f \.7$ | f \.8$ | f \.man$ & t r +1 Display the file with roff -man + %view{ascii,nroff} roff -c -Tlatin1 -mandoc %f + +2 Call the info hypertext browser + info + += t d +3 Compress the current subdirectory (tar.gz) + Pwd=`basename %d /` + echo -n "Name of the compressed file (without extension) [$Pwd]: " + read tar + [ "$tar"x = x ] && tar="$Pwd" + cd .. && \ + tar cf - "$Pwd" | gzip -f9 > "$tar.tar.gz" && \ + echo "../$tar.tar.gz created." + +4 Compress the current subdirectory (tar.bz2) + Pwd=`basename %d /` + echo -n "Name of the compressed file (without extension) [$Pwd]: " + read tar + [ "$tar"x = x ] && tar="$Pwd" + cd .. && \ + tar cf - "$Pwd" | bzip2 -f > "$tar.tar.bz2" && \ + echo "../$tar.tar.bz2 created." + +5 Compress the current subdirectory (tar.7z) + Pwd=`basename %d /` + echo -n "Name of the compressed file (without extension) [$Pwd]: " + read tar + [ "$tar"x = x ] && tar="$Pwd" + cd .. && \ + tar cf - "$Pwd" | 7za a -si "$tar.tar.7z" && \ + echo "../$tar.tar.7z created." + +6 Compress the current subdirectory (tar.xz) + Pwd=`basename %d /` + echo -n "Name of the compressed file (without extension) [$Pwd]: " + read tar + [ "$tar"x = x ] && tar="$Pwd" + cd .. && \ + tar cf - "$Pwd" | xz -f > "$tar.tar.xz" && \ + echo "../$tar.tar.xz created." + +7 Compress the current subdirectory (tar.zst) + Pwd=`basename %d /` + echo -n "Name of the compressed file (without extension) [$Pwd]: " + read tar + [ "$tar"x = x ] && tar="$Pwd" + cd .. && \ + tar cf - "$Pwd" | zstd -f > "$tar.tar.zst" && \ + echo "../$tar.tar.zst created." + += f \.c$ & t r ++ f \.c$ & t r & ! t t +c Compile and link current .c file + make "`basename %f .c`" 2>/dev/null || cc -O -o "`basename %f .c`" %f + ++ t r & ! t t +a Append file to opposite + cat %f >> %D/%f + ++ t t +A Append files to opposite files + for i in %t ; do + cat "$i" >> %D/"$i" + done + ++ t r & ! t t +d Delete file if a copy exists in the other directory. + if [ %d = %D ]; then + echo "The two directories must be different." + exit 1 + fi + if [ -f %D/%f ]; then # if two of them, then + if cmp -s %D/%f %f; then + rm %f && echo %f": DELETED." + else + echo %f" and "%D/%f" differ: NOT deleted." + echo -n "Press RETURN " + read key + fi + else + echo %f": No copy in "%D/%f": NOT deleted." + fi + ++ t t +D Delete tagged files if a copy exists in the other directory. + if [ %d = %D ]; then + echo "The two directores must be different." + exit 1 + fi + for i in %t ; do + if [ -f %D/"$i" ]; then + SUM1=`sum "$i"` + SUM2=`sum %D/"$i"` + if [ "$SUM1" = "$SUM2" ]; then + rm "$i" && echo "${i}: DELETED." + else + echo "$i and "%D"/$i differ: NOT deleted." + fi + else + echo "$i has no copy in "%D": NOT deleted." + fi + done + +m View manual page + MAN=%{Enter manual name} + %view{ascii,nroff} MANROFFOPT='-c -Tlatin1' MAN_KEEP_FORMATTING=1 man -P cat "$MAN" + += f \.gz$ & t r ++ ! t t +n Inspect gzip'ed newsbatch file + dd if=%f bs=1 skip=12 | zcat | ${PAGER-more} + # assuming the cunbatch header is 12 bytes long. + += t r & ++ ! t t +h Strip headers from current newsarticle + CHECK=`awk '{print $1 ; exit}' %f` 2>/dev/null + case "$CHECK" in + Newsgroups:|Path:) + I=`mktemp "${MC_TMPDIR:-/tmp}/news.XXXXXX"` || exit 1 + cp %f "$I" && sed '/^'"$CHECK"' /,/^$/d' "$I" > %f + [ "$?" = "0" ] && rm "$I" + echo %f": header removed." + ;; + *) + echo %f" is not a news article." + ;; + esac + ++ t t +H Strip headers from the marked newsarticles + for i in %t ; do + CHECK=`awk '{print $1 ; exit}' "$i"` 2>/dev/null + WFILE=`mktemp "${MC_TMPDIR:-/tmp}/news.XXXXXX"` || exit 1 + case "$CHECK" in + Newsgroups:|Path:) + cp "$i" "$WFILE" && sed '/^'"$CHECK"' /,/^$/d' "$WFILE" > "$i" + if [ "$?" = "0" ]; then + rm "$WFILE"; echo "$i header removed. OK." + else + echo "Oops! Please check $i against $WFILE." + fi + ;; + *) + echo "$i skipped: Not a news article." + ;; + esac + done + += t r ++ ! t t +r Copy file to remote host + echo -n "To which host?: " + read Host + echo -n "To which directory on $Host?: " + read Dir + rcp -p %f "${Host}:${Dir}" + ++ t t +R Copy files to remote host (no error checking) + echo -n "Copy files to which host?: " + read Host + echo -n "To which directory on $Host? :" + read Dir + rcp -pr %u "${Host}:${Dir}" + += f \.tex$ & t r ++ f \.tex$ & t r & ! t t +t Run latex on file and show it with xdvi + latex %f && xdvi "`basename %f .tex`".dvi + +=+ f ^part | f ^Part | f uue & t r ++ t t +U Uudecode marked news articles (needs work) + ( + for i in %t ; do # strip headers + FIRST=`awk '{print $1 ; exit}' "$i"` + cat "$i" | sed '/^'"$FIRST"' /,/^$/d' + done + ) | sed '/^$/d' | sed -n '/^begin 6/,/^end$/p' | uudecode + if [ "$?" != "0" ]; then + echo "Cannot decode "%t"." + fi + echo "Please test the output file before deleting anything." + +=+ f \.tar\.gz$ | f \.tar\.z$ | f \.tgz$ | f \.tpz$ | f \.tar\.lz$ | f \.tar\.lz4$ | f \.tar\.lzma$ | f \.tar\.7z$ | f \.tar\.xz$ | f \.tar\.zst | f \.tar\.Z$ | f \.tar\.bz2$ & t rl +x Extract the contents of a compressed tar file + unset PRG + case %f in + *.tar.7z) PRG="7za e -so";; + *.tar.bz2) PRG="bunzip2 -c";; + *.tar.gz|*.tar.z|*.tgz|*.tpz|*.tar.Z) PRG="gzip -dc";; + *.tar.lz) PRG="lzip -dc";; + *.tar.lz4) PRG="lz4 -dc";; + *.tar.lzma) PRG="lzma -dc";; + *.tar.xz) PRG="xz -dc";; + *.tar.zst) PRG="zstd -dc";; + *) exit 1;; + esac + $PRG %f | tar xvf - + += t r ++ ! t t +y Gzip or gunzip current file + unset DECOMP + case %f in + *.gz|*.[zZ]) DECOMP=-d;; + esac + # Do *not* add quotes around $DECOMP! + gzip $DECOMP -v %f + ++ t t +Y Gzip or gunzip tagged files + for i in %t ; do + unset DECOMP + case "$i" in + *.gz|*.[zZ]) DECOMP=-d;; + esac + gzip $DECOMP -v "$i" + done + ++ ! t t +b Bzip2 or bunzip2 current file + unset DECOMP + case %f in + *.bz2) DECOMP=-d;; + esac + bzip2 $DECOMP -v %f + ++ t t +B Bzip2 or bunzip2 tagged files + for i in %t ; do + unset DECOMP + case "$i" in + *.bz2) DECOMP=-d;; + esac + bzip2 $DECOMP -v "$i" + done + ++ f \.tar.gz$ | f \.tgz$ | f \.tpz$ | f \.tar.Z$ | f \.tar.z$ | f \.tar.bz2$ | f \.tar.F$ & t r & ! t t +z Extract compressed tar file to subdirectory + unset D + set gzip -cd + case %f in + *.tar.F) D=`basename %f .tar.F`; set freeze -dc;; + *.tar.Z) D=`basename %f .tar.Z`;; + *.tar.bz2) D=`basename %f .tar.bz2`; set bunzip2 -c;; + *.tar.gz) D=`basename %f .tar.gz`;; + *.tar.z) D=`basename %f .tar.z`;; + *.tgz) D=`basename %f .tgz`;; + *.tpz) D=`basename %f .tpz`;; + esac + mkdir "$D"; cd "$D" && ("$1" "$2" ../%f | tar xvf -) + ++ t t +Z Extract compressed tar files to subdirectories + for i in %t ; do + set gzip -dc + unset D + case "$i" in + *.tar.F) D=`basename "$i" .tar.F`; set freeze -dc;; + *.tar.Z) D=`basename "$i" .tar.Z`;; + *.tar.bz2) D=`basename "$i" .tar.bz2`; set bunzip2 -c;; + *.tar.gz) D=`basename "$i" .tar.gz`;; + *.tar.z) D=`basename "$i" .tar.z`;; + *.tgz) D=`basename "$i" .tgz`;; + *.tpz) D=`basename "$i" .tpz`;; + esac + mkdir "$D"; (cd "$D" && "$1" "$2" "../$i" | tar xvf -) + done + ++ f \.gz$ | f \.tgz$ | f \.tpz$ | f \.Z$ | f \.z$ | f \.bz2$ & t r & ! t t +c Convert gz<->bz2, tar.gz<->tar.bz2 & tgz->tar.bz2 + unset D + unset EXT + case %f in + *.Z) EXT=Z;; + *.bz2) EXT=bz2;; + *.gz) EXT=gz;; + *.tgz) EXT=tgz;; + *.tpz) EXT=tpz;; + *.z) EXT=z;; + esac + case "$EXT" in + bz2|Z|gz|z) D=`basename %f ."$EXT"`;; + tgz|tpz) D=`basename %f ."$EXT"`.tar;; + esac + if [ "$EXT" = "bz2" ]; then + bunzip2 -v %f + gzip -f9 -v "$D" + else + gunzip -v %f + bzip2 -v "$D" + fi + ++ t t +C Convert gz<->bz2, tar.gz<->tar.bz2 & tgz->tar.bz2 + for i in %t ; do + unset D + unset EXT + case "$i" in + *.Z) EXT=Z;; + *.bz2) EXT=bz2;; + *.gz) EXT=gz;; + *.tgz) EXT=tgz;; + *.tpz) EXT=tpz;; + *.z) EXT=z;; + esac + case "$EXT" in + bz2|Z|gz|z) D=`basename "$i" ."$EXT"`;; + tgz|tpz) D=`basename "$i" ."$EXT"`.tar;; + esac + if [ "$EXT" = "bz2" ]; then + bunzip2 -v "$i" + gzip -f9 -v "$D" + else + gunzip -v "$i" + bzip2 -v "$D" + fi + done + ++ x /usr/bin/open | x /usr/local/bin/open & x /bin/sh +o Open next a free console + open -s -- sh + ++ x /usr/bin/open | x /usr/local/bin/open & x /bin/sh +O Odoo Refresh + sh /root/refresh_odoo.sh + ++ x /usr/bin/open | x /usr/local/bin/open & x /bin/sh +G git push + git push -u origin main + + diff --git a/views/dss_addstructures.xml b/views/dss_addstructures.xml new file mode 100755 index 0000000..046b7f9 --- /dev/null +++ b/views/dss_addstructures.xml @@ -0,0 +1,72 @@ + + + + + dss_adstructures_form + dss.adstructures + + +

+ + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + dss_adstructures_tree + dss.adstructures + + + + + + + + + + + DigitalSignage Werbestrukturen + ir.actions.act_window + dss.adstructures + tree,form + {} + +

+ Neuen Medienfiletyp erstellen +

+
+
+ + + + diff --git a/views/dss_ads.xml b/views/dss_ads.xml new file mode 100755 index 0000000..40d3503 --- /dev/null +++ b/views/dss_ads.xml @@ -0,0 +1,324 @@ + + + + + dss_ads_form + dss.ads + + +
+
+
+ +
+
+ + + + +
+
+
+
+
+
+
+ + + +
+
+ + + +
+
+
+
+ + + +
+
+
+
+ + + +
+
+ +
+
+ +
+
+
+
+
+ + + +
+
+ + + +
+
+ + + +
+ +
+ + + +
+
+ + + +
+
+ + + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
+
+
+ + + dss_projects_tree + dss.ads + + + + + + + + + + + + + + + + Standard Beschreibung 1 + + + form + code + + action = records.setStandardText("AD_STD_1") + + + + + + Standard Beschreibung 2 + + + form + code + + action = records.setStandardText("AD_STD_2") + + + + + Standard Beschreibung 3 + + + form + code + + action = records.setStandardText("AD_STD_3") + + + + + + + dss_ads_kanban + dss.ads + + + + + + + + +
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+ + + + DigitalSignage Werbekampagnen Gesamtansicht + ir.actions.act_window + dss.ads + kanban + {} + + + + DigitalSignage Werbekampagnen Gesamtansicht + ir.actions.act_window + dss.ads + form + {} + + + + DigitalSignage Werbekampagnen + ir.actions.act_window + dss.ads + tree,form,kanban + {} + +

+ Neue Werbekampagne erstellen +

+
+
+ + + +
diff --git a/views/dss.xml b/views/dss_contracts.xml similarity index 70% rename from views/dss.xml rename to views/dss_contracts.xml index 85c196f..973c87e 100755 --- a/views/dss.xml +++ b/views/dss_contracts.xml @@ -128,6 +128,9 @@
+
+

@@ -322,7 +325,7 @@

- +
@@ -358,6 +361,26 @@
+
> +
+
+ + + + +
+
+
+ +-- + + + + + + + + @@ -375,6 +398,9 @@
+ + +
@@ -422,7 +448,8 @@
- + +
@@ -451,153 +478,4 @@ - - - - - dss_projects_form - dss.projects - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
- - - dss_projects_tree - dss.projects - - - - - - - - - - - - - - - dss_projects_kanban - dss.projects - - - - - - - - - - -
- - - - - - - - - - diff --git a/views/dss_mediafiles.xml b/views/dss_mediafiles.xml new file mode 100755 index 0000000..8893168 --- /dev/null +++ b/views/dss_mediafiles.xml @@ -0,0 +1,72 @@ + + + + + dss_mediatypes_form + dss.mediatypes + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + + dss_mediatypes_tree + dss.mediatypes + + + + + + + + + + + + DigitalSignage Mediendateitypen + ir.actions.act_window + dss.mediatypes + tree,form + {} + +

+ Neuen Medienfiletyp erstellen +

+
+
+ + +
diff --git a/views/dss_projects.xml b/views/dss_projects.xml new file mode 100755 index 0000000..6d0dc3a --- /dev/null +++ b/views/dss_projects.xml @@ -0,0 +1,164 @@ + + + + + dss_projects_form + dss.projects + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + + + dss_projects_kanban + dss.projects + + + + + + + + + + +
+
+
+
+ + +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+ +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+ + + dss_projects_tree + dss.projects + + + + + + + + + + + + + + + + + + + + + DigitalSignage Projekte + ir.actions.act_window + dss.projects + kanban,form,tree + {} + +

+ Fuege ein System ein ! +

+
+
+ +
diff --git a/views/dss_projectstate.xml b/views/dss_projectstate.xml new file mode 100755 index 0000000..e711e38 --- /dev/null +++ b/views/dss_projectstate.xml @@ -0,0 +1,55 @@ + + + + + dss_projectstate_tree + dss.projectstate + + + + + + + + + + + + + dss_projectstate_form + dss.projectstate + +
+ + + + + + + + + + +
+ + + +
+
+
+
+ + + DigitalSignage Projectstatus + ir.actions.act_window + dss.projectstate + tree,form + {} + +

+ Neuen Projektstatus erstellen +

+
+
+ +
diff --git a/views/dss_systemtypen.xml b/views/dss_systemtypen.xml new file mode 100755 index 0000000..68c3d61 --- /dev/null +++ b/views/dss_systemtypen.xml @@ -0,0 +1,60 @@ + + + + + dss_systemtypen_tree + dss.systemtypen + + + + + + + + + + + + + + + dss_systemtypen_form + dss.systemtypen + +
+ + + + + + + + + + + + +
+ +
+
+
+
+ + + DigitalSignage Systemtypen + ir.actions.act_window + dss.systemtypen + tree,form + {} + +

+ Neuen Systemtyp erstellen +

+
+
+ + +
diff --git a/views/dss_texts.xml b/views/dss_texts.xml new file mode 100755 index 0000000..082e2f9 --- /dev/null +++ b/views/dss_texts.xml @@ -0,0 +1,68 @@ + + + + + dss_texts_form + dss.texts + + +
+ + + + + + + + + + + + + + + + +
+ + + +
+
+
+
+ + + dss_texts_tree + dss.texts + + + + + + + + + + + + DigitalSignage Standardtexte + ir.actions.act_window + dss.texts + tree,form + {} + +

+ Neuen Standardtext erstellen +

+
+
+ + + +
diff --git a/views/mainsystem_view.xml b/views/mainsystem_view.xml index 4b81981..291de8c 100755 --- a/views/mainsystem_view.xml +++ b/views/mainsystem_view.xml @@ -52,7 +52,7 @@ - + @@ -87,6 +87,9 @@
+ + +
@@ -160,30 +163,14 @@
+ + +
- - dss_systemtypen_form - dss.systemtypen - -
- - - - - - - - - -
-
-
-
-
dss_systems_tree @@ -225,6 +212,9 @@
+ + +
@@ -244,53 +234,6 @@ - - dss_systemtypen_tree - dss.systemtypen - - - - - - - - - - - - - - dss_projectstate_tree - dss.projectstate - - - - - - - - - - - - dss_projectstate_form - dss.projectstate - -
- - - - - - - - - -
-
-
-
-
dss_contractstate_tree @@ -298,7 +241,7 @@ - + @@ -315,13 +258,56 @@ - +
+ + + +
+ +
+
+ + + dss_adstate_tree + dss.adstate + + + + + + + + + + + + + + dss_adstate_form + dss.adstate + +
+ + + + + + + + + + + +
+ + +
@@ -333,7 +319,7 @@ - + @@ -356,6 +342,9 @@
+ + +
@@ -367,7 +356,7 @@ - + @@ -392,6 +381,9 @@
+ + +
@@ -430,6 +422,9 @@
+ + +
@@ -465,26 +460,96 @@
+ + +
- - - - DigitalSignage Projekte - ir.actions.act_window - dss.projects - kanban,form,tree - {} - -

- Fuege ein System ein ! -

+ + dss_paysystem_fields_tree + dss.paysystem_fields + + + + + + + + + + + dss_paymentsystem_fields_form + dss.paysystem_fields + +
+ + + + + + + + + + + +
+ + + +
+
+
+
+ + + dss_paysystems_tree + dss.paysystems + + + + + + + + + + + + + dss_paymentsystems_form + dss.paysystems + +
+ + + + + + + + + + + + + +
+ + + +
+
+
+
+ + DigitalSignage Systeme ir.actions.act_window @@ -524,31 +589,6 @@
- - DigitalSignage Systemtypen - ir.actions.act_window - dss.systemtypen - tree,form - {} - -

- Neuen Systemtyp erstellen -

-
-
- - - DigitalSignage Projectstatus - ir.actions.act_window - dss.projectstate - tree,form - {} - -

- Neuen Projektstatus erstellen -

-
-
DigitalSignage Vertragsstatus @@ -563,6 +603,21 @@ + + DigitalSignage Werbeaktions-Status + ir.actions.act_window + dss.adstate + tree,form + {} + +

+ Neuen Werbeaktions-Status erstellen +

+
+
+ + + DigitalSignage Bearbeitungsstatus ir.actions.act_window @@ -615,106 +670,58 @@ - + + DigitalSignage Zahlungsfelder + ir.actions.act_window + dss.paysystem_fields + tree,form + {} + +

+ Neues Zahlfeld erstellen +

+
+
- + + DigitalSignage Zahlungsart + ir.actions.act_window + dss.paysystems + tree,form + {} + +

+ Neue Zahlugnsart erstellen +

+
+
- + + email.dss.template.search + mail.template + + + + + + + + + + + + + - + + Email Templates + mail.template + form,tree + + + {'search_default_payment_templates': 1} + - - - - - - - - - - - - - - - - - - - - diff --git a/views/menu.xml b/views/menu.xml index 02ab84b..58cca57 100755 --- a/views/menu.xml +++ b/views/menu.xml @@ -6,4 +6,176 @@ web_icon="digitalsignage_system,static/description/icon.png" sequence="2"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file