From 7f5db6b928acc4a9f519c8f5d7d378e62abc082f Mon Sep 17 00:00:00 2001
From: Mark Pittaway
Date: Mon, 6 May 2024 17:20:48 +1000
Subject: [PATCH] [STTNHUB-336] improve: Group content to single coverage by
STT Article ID
---
server/features/ingest_planning.feature | 155 +++++++-------
server/stt/parser.py | 7 +-
server/stt/signal_hooks.py | 189 +++++++++++++-----
server/stt/stt_planning_ml.py | 1 +
.../fixtures/stt_newsml_link_content.xml | 3 +-
.../fixtures/stt_newsml_link_content_2.xml | 126 ++++++++++++
.../stt_newsml_link_content_with_topic_id.xml | 2 +-
.../fixtures/stt_newsml_online_version.xml | 2 +-
8 files changed, 357 insertions(+), 128 deletions(-)
create mode 100644 server/tests/fixtures/stt_newsml_link_content_2.xml
diff --git a/server/features/ingest_planning.feature b/server/features/ingest_planning.feature
index 54ff3dc..96bb8eb 100644
--- a/server/features/ingest_planning.feature
+++ b/server/features/ingest_planning.feature
@@ -328,7 +328,7 @@ Feature: Ingest STT Planning items
@auth
@stt_cvs
@stt_providers
- Scenario: Link ingested coverages to content on update
+ Scenario: Creates new coverage on content ingest
# Ingest Planning with 0 coverages (1 placeholder)
When we fetch from "STTPlanningML" ingest "planning_ml_before_link_content.xml"
When we get "/planning"
@@ -345,21 +345,10 @@ Feature: Ingest STT Planning items
When we get "/assignments"
Then we get list with 0 items
# Ingest content
- When we fetch from "STTNewsML" ingest "stt_newsml_link_content.xml" using routing_scheme
+ When we fetch from "STTNewsML" ingest "stt_newsml_link_content_with_topic_id.xml" using routing_scheme
"""
#routing_schemes._id#
"""
- When we get "published"
- Then we get list with 1 items
- """
- {"_items": [{
- "uri": "urn:newsml:stt.fi:101801633",
- "assignment_id": "__no_value__"
- }]}
- """
- When we get "/assignments"
- Then we get list with 0 items
- When we fetch from "STTPlanningML" ingest "planning_ml_link_content.xml"
When we get "/assignments"
Then we get list with 1 items
"""
@@ -374,6 +363,14 @@ Feature: Ingest STT Planning items
}]}
"""
Then we store "assignment" with first item
+ When we get "published"
+ Then we get list with 1 items
+ """
+ {"_items": [{
+ "uri": "urn:newsml:stt.fi:101801633",
+ "assignment_id": "#assignment._id#"
+ }]}
+ """
When we get "/planning"
Then we get list with 1 items
"""
@@ -387,6 +384,21 @@ Feature: Ingest STT Planning items
"user": null,
"state": "completed",
"priority": 6
+ },
+ "news_coverage_status": {"qcode": "ncostat:int", "name": "coverage intended"},
+ "workflow_status": "active",
+ "flags": {"placeholder": "__no_value__"},
+ "planning": {
+ "g2_content_type": "text",
+ "scheduled": "2017-12-25T09:16:43+0000",
+ "slugline": "Parliament passed the Alcohol Act and the government gained confidence*** TRANSLATED ***",
+ "genre": [{"name": "P\u00e4\u00e4juttu", "qcode": "1"}],
+ "subject": [
+ {"name": "Politics", "qcode": "9", "scheme": "sttdepartment"},
+ {"name": "Pika+", "qcode": "1", "scheme": "sttversion"},
+ {"name": "Suomi", "qcode": "1", "scheme": "country"},
+ {"name": "Eurooppa", "qcode": "150", "scheme": "world_region"}
+ ]
}
}],
"extra": {
@@ -394,36 +406,23 @@ Feature: Ingest STT Planning items
}
}]}
"""
- When we get "published"
- Then we get list with 1 items
- """
- {"_items": [{
- "uri": "urn:newsml:stt.fi:101801633",
- "assignment_id": "#assignment._id#"
- }]}
- """
@auth
@stt_cvs
@stt_providers
- Scenario: Creates new coverage on content ingest
- # Ingest Planning with 0 coverages (1 placeholder)
- When we fetch from "STTPlanningML" ingest "planning_ml_before_link_content.xml"
+ Scenario: Groups content to a single coverage based on STT Article ID
+ When we fetch from "STTPlanningML" ingest "planning_ml_link_content.xml"
+ When we get "/assignments"
+ Then we get list with 0 items
When we get "/planning"
Then we get list with 1 items
"""
{"_items": [{
"_id": "urn:newsml:stt.fi:437036",
- "coverages": [{
- "assigned_to": "__empty__",
- "flags": {"placeholder": true}
- }]
+ "coverages": [{"coverage_id": "ID_TEXT_120123822"}]
}]}
"""
- When we get "/assignments"
- Then we get list with 0 items
- # Ingest content
- When we fetch from "STTNewsML" ingest "stt_newsml_link_content_with_topic_id.xml" using routing_scheme
+ When we fetch from "STTNewsML" ingest "stt_newsml_link_content.xml" using routing_scheme
"""
#routing_schemes._id#
"""
@@ -432,55 +431,67 @@ Feature: Ingest STT Planning items
"""
{"_items": [{
"planning_item": "urn:newsml:stt.fi:437036",
- "coverage_item": "ID_TEXT_101801633",
- "priority": 6,
- "assigned_to": {
- "desk": "#desks._id#",
- "state": "completed"
- }
+ "coverage_item": "ID_TEXT_120123822"
}]}
"""
- Then we store "assignment" with first item
- When we get "published"
+ Then we store "assignment_1" with first item
+ When we get "/planning"
Then we get list with 1 items
"""
{"_items": [{
- "uri": "urn:newsml:stt.fi:101801633",
- "assignment_id": "#assignment._id#"
+ "_id": "urn:newsml:stt.fi:437036",
+ "coverages": [{
+ "coverage_id": "ID_TEXT_120123822",
+ "assigned_to": {"assignment_id": "#assignment_1._id#"}
+ }]
}]}
"""
- When we get "/planning"
+ When we get "published"
Then we get list with 1 items
"""
{"_items": [{
- "_id": "urn:newsml:stt.fi:437036",
- "coverages": [{
- "coverage_id": "ID_TEXT_101801633",
- "assigned_to": {
- "assignment_id": "#assignment._id#",
- "desk": "#desks._id#",
- "user": null,
- "state": "completed",
- "priority": 6
- },
- "news_coverage_status": {"qcode": "ncostat:int", "name": "coverage intended"},
- "workflow_status": "active",
- "flags": {"placeholder": "__no_value__"},
- "planning": {
- "g2_content_type": "text",
- "scheduled": "2017-12-25T09:16:43+0000",
- "slugline": "Parliament passed the Alcohol Act and the government gained confidence*** TRANSLATED ***",
- "genre": [{"name": "P\u00e4\u00e4juttu", "qcode": "1"}],
- "subject": [
- {"name": "Politics", "qcode": "9", "scheme": "sttdepartment"},
- {"name": "Pika+", "qcode": "1", "scheme": "sttversion"},
- {"name": "Suomi", "qcode": "1", "scheme": "country"},
- {"name": "Eurooppa", "qcode": "150", "scheme": "world_region"}
- ]
- }
- }],
- "extra": {
- "stt_topics": "437036"
- }
+ "uri": "urn:newsml:stt.fi:101801633",
+ "assignment_id": "#assignment_1._id#"
}]}
"""
+ And we store "content_1" with first item
+ When we fetch from "STTNewsML" ingest "stt_newsml_link_content_2.xml" using routing_scheme
+ """
+ #routing_schemes._id#
+ """
+ When we get "published"
+ Then we get list with 2 items
+ And we store "content_1" with 1 item
+ And we store "content_2" with 2 item
+ When we get "/assignments"
+ Then we get list with 2 items
+ """
+ {"_items": [
+ {
+ "planning_item": "urn:newsml:stt.fi:437036",
+ "coverage_item": "ID_TEXT_120123822",
+ "item_ids": ["#content_1.guid#"]
+ },
+ {
+ "planning_item": "urn:newsml:stt.fi:437036",
+ "coverage_item": "ID_TEXT_120123822",
+ "item_ids": ["#content_2.guid#"]
+ }
+ ]}
+ """
+ And we store "assignment_1" with 1 item
+ And we store "assignment_2" with 2 item
+ When we get "published"
+ Then we get list with 2 items
+ """
+ {"_items": [
+ {
+ "uri": "urn:newsml:stt.fi:101801633",
+ "assignment_id": "#assignment_1._id#"
+ },
+ {
+ "uri": "urn:newsml:stt.fi:101801733",
+ "assignment_id": "#assignment_2._id#"
+ }
+ ]}
+ """
diff --git a/server/stt/parser.py b/server/stt/parser.py
index 40473a3..1313b2c 100644
--- a/server/stt/parser.py
+++ b/server/stt/parser.py
@@ -77,9 +77,10 @@ def set_extra_fields(self, item, xml):
# newsItem altId
try:
- alt_id = xml.find(self.qname('contentMeta')).find(self.qname('altId')).text
- if alt_id:
- item.setdefault('extra', {})['sttidtype_textid'] = alt_id
+ for alt_id in xml.find(self.qname('contentMeta')).findall(self.qname('altId')):
+ if alt_id.get("type") == "sttidtype:textid" and alt_id.text:
+ # textid is STT's Article ID
+ item.setdefault('extra', {})['sttidtype_textid'] = alt_id.text
except AttributeError:
pass
diff --git a/server/stt/signal_hooks.py b/server/stt/signal_hooks.py
index 6d30a40..daa70f9 100644
--- a/server/stt/signal_hooks.py
+++ b/server/stt/signal_hooks.py
@@ -7,10 +7,15 @@
from superdesk import get_resource_service, signals
from superdesk.factory.app import SuperdeskEve
-from superdesk.metadata.utils import generate_guid
-from superdesk.metadata.item import GUID_NEWSML, CONTENT_STATE
-
-from planning.common import WORKFLOW_STATE, ASSIGNMENT_WORKFLOW_STATE, get_coverage_status_from_cv
+from superdesk.metadata.item import CONTENT_STATE
+
+from planning.common import (
+ WORKFLOW_STATE,
+ ASSIGNMENT_WORKFLOW_STATE,
+ get_coverage_status_from_cv,
+ post_required,
+ update_post_item,
+)
from planning.signals import planning_ingested
from stt.stt_planning_ml import STTPlanningMLParser
@@ -99,9 +104,8 @@ def link_coverages_to_content(_sender: Any, item: Dict[str, Any], original: Opti
# Update the planning item with the latest Assignment information, and link the coverages to the content
try:
updated_item = planning_service.patch(planning_id, updates)
- except Exception as err:
- logger.exception(err)
- logger.error("Failed to update planning with newly linked coverages")
+ except Exception:
+ logger.exception("Failed to update planning with newly linked coverages")
return
for coverage in updated_item.get("coverages") or []:
@@ -145,6 +149,8 @@ def before_content_published(_sender: Any, item: Dict[str, Any], updates: Dict[s
"assignment_id": None
})
+ assignment_id = None
+
if deliveries.count():
planning_id = deliveries[0].get("planning_id")
coverage_id = deliveries[0].get("coverage_id")
@@ -163,10 +169,14 @@ def before_content_published(_sender: Any, item: Dict[str, Any], updates: Dict[s
planning = planning_service.find_one(req=None, _id=planning_id)
if not planning:
- logger.warning(f"Failed to link content to coverage: planning item '{planning_id}' not found")
+ logger.warning("Failed to link content to coverage: Planning item not found", extra=dict(
+ content_guid=item.get("guid"),
+ planning_id=planning_id,
+ ))
return
planning_updates = {"coverages": deepcopy(planning.get("coverages") or [])}
+ update_planning_item = True
if coverage_id is not None:
coverage = next(
(
@@ -177,7 +187,11 @@ def before_content_published(_sender: Any, item: Dict[str, Any], updates: Dict[s
None
)
if coverage is None:
- logger.warning(f"Failed to find coverage '{coverage_id}' in planning item '{planning_id}'")
+ logger.warning("Failed to find coverage in planning item", extra=dict(
+ content_guid=item.get("guid"),
+ planning_id=planning_id,
+ coverage_id=coverage_id,
+ ))
return
_copy_metadata_from_article_to_coverage(coverage, item)
@@ -185,48 +199,124 @@ def before_content_published(_sender: Any, item: Dict[str, Any], updates: Dict[s
else:
# Set the metadata for the new coverage
try:
- content_id = item["uri"].split(":")[-1]
- coverage_id = f"ID_TEXT_{content_id}"
- except (KeyError, AttributeError, IndexError, TypeError):
- # Unable to determine the ID for the item
- # Create a new CoverageID
- coverage_id = generate_guid(type=GUID_NEWSML)
- new_coverage = {
- "coverage_id": coverage_id,
- "planning": {"g2_content_type": "text"},
- "news_coverage_status": get_coverage_status_from_cv("ncostat:int"),
- "flags": {},
- }
- _copy_metadata_from_article_to_coverage(new_coverage, item)
- _update_coverage_assignment_details(new_coverage, item)
-
- # Remove placeholder text coverage and add the new one
- planning_updates["coverages"] = [
- coverage
- for coverage in planning_updates["coverages"]
- if not (coverage.get("flags") or {}).get("placeholder")
- ] + [new_coverage]
+ stt_article_id = item["extra"]["sttidtype_textid"]
+ coverage_id = f"ID_TEXT_{stt_article_id}"
+ except (KeyError, TypeError):
+ logger.error("Failed to find the STT Article ID from the content, unable to continue", extra=dict(
+ content_guid=item.get("guid"),
+ planning_id=planning_id,
+ ))
+ return
- try:
- updated_planning = planning_service.patch(planning_id, planning_updates)
- except Exception as err:
- logger.exception(err)
- logger.error("Failed to update planning with newly linked coverages")
- return
+ existing_coverage = next(
+ (
+ coverage
+ for coverage in planning_updates["coverages"]
+ if coverage.get("coverage_id") == coverage_id
+ ),
+ None
+ )
+ if existing_coverage:
+ # A Coverage ID with STT's Article ID already exists
+ # Use that to link this content to
+ try:
+ coverage_has_assignment = bool(existing_coverage["assigned_to"]["assignment_id"])
+ except (KeyError, TypeError):
+ coverage_has_assignment = False
+
+ if not coverage_has_assignment:
+ # No Assignment currently exists, add ``assigned_to`` details so the Planning module
+ # will automatically create one for us
+ _copy_metadata_from_article_to_coverage(existing_coverage, item)
+ _update_coverage_assignment_details(existing_coverage, item)
+ else:
+ # An Assignment already exists for this coverage,
+ # Add another Assignment for this coverage, and link it to the content
+ try:
+ assignment_id = get_resource_service("assignments").post([{
+ "assigned_to": {
+ "desk": (item.get("task") or {}).get("desk"),
+ "state": ASSIGNMENT_WORKFLOW_STATE.COMPLETED,
+ },
+ "planning_item": planning_id,
+ "coverage_item": coverage_id,
+ "planning": deepcopy(existing_coverage.get("planning")),
+ "priority": (
+ item.get("priority") or
+ (existing_coverage.get("assigned_to") or {}).get("priority") or
+ 2
+ ),
+ "description_text": planning.get("description_text")
+ }])[0]
+ except Exception:
+ logger.exception("Failed to create the new Assignment", extra=dict(
+ content_guid=item.get("guid"),
+ planning_id=planning_id,
+ coverage_id=coverage_id,
+ ))
+ return
+
+ # No need to update Planning item directly, as there are no changes to coverages
+ # Only changes to coverage assignments & deliveries (which is held in a different resource collection)
+ update_planning_item = False
+ else:
+ new_coverage = {
+ "coverage_id": coverage_id,
+ "planning": {"g2_content_type": "text"},
+ "news_coverage_status": get_coverage_status_from_cv("ncostat:int"),
+ "flags": {},
+ }
+
+ _copy_metadata_from_article_to_coverage(new_coverage, item)
+ _update_coverage_assignment_details(new_coverage, item)
+
+ # Remove placeholder text coverage and add the new one
+ planning_updates["coverages"] = [
+ coverage
+ for coverage in planning_updates["coverages"]
+ if not (coverage.get("flags") or {}).get("placeholder")
+ ] + [new_coverage]
- assignment_id = next(
- (coverage for coverage in updated_planning.get("coverages", []) if coverage.get("coverage_id") == coverage_id),
- {}
- ).get("assigned_to", {}).get("assignment_id")
- if not assignment_id:
- logger.warning(f"Failed to get 'assignment_id' of coverage '{coverage_id}'")
- return
+ if update_planning_item:
+ try:
+ updated_planning = planning_service.patch(planning_id, planning_updates)
+ except Exception as err:
+ logger.exception(err)
+ logger.error("Failed to update planning with newly linked coverages")
+ return
+ else:
+ updated_planning = planning_updates
+ if post_required(planning, planning):
+ # Re-publish the Planning item (if required)
+ # This way the updated coverage deliveries will be re-published to subscribers
+ update_post_item(planning, planning)
+
+ if assignment_id is None:
+ # Assignment ID is not currently known, grab it from the latest Coverage information
+ assignment_id = next(
+ (
+ coverage
+ for coverage in updated_planning.get("coverages", [])
+ if coverage.get("coverage_id") == coverage_id
+ ),
+ {}
+ ).get("assigned_to", {}).get("assignment_id")
+ if not assignment_id:
+ logger.error("Failed to get 'assignment_id' of coverage", extra=dict(
+ content_guid=item.get("guid"),
+ planning_id=planning_id,
+ coverage_id=coverage_id,
+ ))
+ return
try:
_link_assignment_and_content(assignment_id, coverage_id, item.get("guid"), True)
- except Exception as err:
- logger.exception(err)
- logger.error("Failed to link coverage assignment to content")
+ except Exception:
+ logger.exception("Failed to link coverage assignment to content", extra=dict(
+ content_guid=item.get("guid"),
+ planning_id=planning_id,
+ coverage_id=coverage_id,
+ ))
return
item["assignment_id"] = assignment_id
@@ -267,9 +357,8 @@ def _get_content_item_by_uris(uris: List[str]) -> Optional[Dict[str, Any]]:
if cursor.count():
return cursor[0]
- except Exception as err:
- logger.exception(err)
- logger.error("Failed to retrieve list of content based on URIs")
+ except Exception:
+ logger.exception("Failed to retrieve list of content based on URIs", extra=dict(uris=uris))
return None
@@ -314,7 +403,7 @@ def _link_assignment_and_content(
):
"""Remove all temporary delivery entries for this coverage and link assignment and content"""
- get_resource_service("delivery").delete_action(lookup={"coverage_id": coverage_id})
+ get_resource_service("delivery").delete_action(lookup={"coverage_id": coverage_id, "assignment_id": None})
get_resource_service("assignments_link").post([{
"assignment_id": assignment_id,
"item_id": content_id,
diff --git a/server/stt/stt_planning_ml.py b/server/stt/stt_planning_ml.py
index 233c375..c5bd319 100644
--- a/server/stt/stt_planning_ml.py
+++ b/server/stt/stt_planning_ml.py
@@ -158,6 +158,7 @@ def _create_temp_assignment_deliveries(
"planning_id": planning_id,
"coverage_id": coverage_id,
"item_id": content_uri,
+ "assignment_id": None,
}
)
diff --git a/server/tests/fixtures/stt_newsml_link_content.xml b/server/tests/fixtures/stt_newsml_link_content.xml
index 9ef4c0c..7ef4973 100644
--- a/server/tests/fixtures/stt_newsml_link_content.xml
+++ b/server/tests/fixtures/stt_newsml_link_content.xml
@@ -18,7 +18,8 @@
32017-12-19T10:33:04+02:002017-12-25T11:16:43+02:00
-114791381
+120123822
+Helsinki
diff --git a/server/tests/fixtures/stt_newsml_link_content_2.xml b/server/tests/fixtures/stt_newsml_link_content_2.xml
new file mode 100644
index 0000000..2a53f31
--- /dev/null
+++ b/server/tests/fixtures/stt_newsml_link_content_2.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+ 2017-10-18T11:16:43+02:00
+ 2017-12-19T10:33:04+02:00
+
+ complemented throughout
+
+
+
+
+
+ 3
+ 2017-12-19T10:33:04+02:00
+ 2017-12-25T11:16:43+02:00
+ 120123822
+
+
+ Helsinki
+
+
+ STT
+
+ stt 107
+
+ Politics
+
+
+ Helsinki
+
+
+ Parliament passed the Alcohol Act and the government gained confidence*** TRANSLATED ***
+ STT–
+
+ Pääjuttu
+
+
+ Pika+
+
+
+
+
+
+ Suomi
+
+
+ Eurooppa
+
+
+
+
+
+
+
*** DISCLAIMER: THIS IS AN AUTOMATED TRANSLATION FROM FINNISH ***
+
Also the unemployment law went through
+
The Parliament has approved the Alcohol Act 124-65. There were two absentee voices and eight MPs absent. As early as Friday, Parliament voted for the percentage of alcohol in the grocery store to rise to 5.5.
+
Government parties have previously agreed that the tax on alcohol will be tightened by EUR 100 million, as the maximum percentage of alcoholic beverages sold in the store will increase.
+
In addition to the alcohol percentage, the Alcohol Act includes a significant number of reforms. With the new Alcohol Act, the restaurant can, for example, continue to dispense with a notice until 4 o'clock. The restaurant may be open after one hour of serving.
+
In the future, food stores may also sell non-fermented alcoholic beverages, so-called limousines. The creatures can be open on weekdays for an hour longer, or at night.
+
Parliament also approved the proposal by Hannakaisa Heikkinen (central) that the government should clarify the rules on distance selling of alcohol. The distance selling was left unclear in the bill and in the report on it. The family and basic minister Annika Saarikko (center) has already announced that she will set up a distance marketing team to investigate.
+
"The will of the government is that we do not want to break Alko's monopoly with any of the risk factors that distance selling could include. If the sales of spirits in Finland are limited
+ Alkoon, the same applies to foreign journalists, Saarikko said on Friday.
+
+
Distance selling means the purchase of alcohol from another EU Member State so that the seller is responsible for the transport of drinks or the organization of transport to the purchaser.
+
Parliament also voted on the government's confidence. The government gained confidence by 106-80. Seven MPs were absent and six were absent.
+
+
+
Rinne: Hallitus runnoi läpi työttömiä kurittavan lain
+
+
+
In the morning's vote, for example, a controversial unemployed security law passed through 103-90. There were two absentee voices and four MPs absent.
+
The opposition has strongly opposed, in particular, the law-related active model, according to which 4.65 percent of the unemployment allowance is reduced if the unemployed person does not qualify for an adequate amount of paid employment or participates in employment promotion services over a period of three months.
+
- The government parties are running the unemployed through a law to cure, despite warnings. We do not accept that the unemployed are punished for the fact that there is simply no job. That is why the SDP will change the active model, Rinne said in a briefing after the vote.
+
+
*** DISCLAIMER: DETTA ÄR EN AUTOMATISK ÖVERSÄTTNING FRÅN FINNISH ***
+
Parlamentet har godkänt alkohollagen 124-65. Det fanns två frånvarande röster och åtta ledamöter frånvarande. Redan i fredags röstade parlamentet för att andelen alkohol i livsmedelsbutiken skulle stiga till 5,5.
+
Regeringspartierna har tidigare kommit överens om att alkoholskatten kommer att stramas med 100 miljoner euro, eftersom den högsta andelen alkoholhaltiga drycker som säljs i affären kommer att öka.
+
Förutom alkoholprocenten innehåller alkohollagen ett betydande antal reformer. Med den nya alkohollagen kan restaurangen till exempel fortsätta att meddela ett meddelande till klockan 4. Restaurangen kan vara öppen efter en timmes servering.
+
I framtiden kan mataffärer också sälja alkoholfria drycker, så kallade limousiner. Varelserna kan vara öppna på vardagar för en timme längre eller på natten.
+
Parlamentet godkände också förslaget från Hannakaisa Heikkinen (central) att regeringen skulle klargöra reglerna för distansförsäljning av alkohol. Distansförsäljningen lämnades oklart i propositionen och rapporten om den. Familjen och grundminister Annika Saarikko (center) har redan meddelat att hon kommer att inrätta ett distansmarknadsföringslag att undersöka.
+
"Regeringens vilja är att vi inte vill bryta Alkos monopol med någon av de riskfaktorer som distansförsäljningen kan innefatta. Om försäljningen av sprit i Finland är begränsad
+
, detsamma gäller utländska journalister, sa Saarikko på fredag.
+
Distansförsäljning innebär inköp av alkohol från en annan EU-medlemsstat så att säljaren är ansvarig för transport av drycker eller transporten till köparen.
+
Parlamentet röstade också om regeringens förtroende. Regeringen fick förtroende med 106-80. Sju parlamentsledamöter var frånvarande och sex var frånvarande.
+
+
+
På morgonens omröstning gick exempelvis en kontroversiell arbetslös säkerhetslag genom 103-90. Det fanns två frånvarande röster och fyra ledamöter frånvarande.
+
Oppositionen har starkt motsatt sig, i synnerhet den lagrelaterade aktiva modellen, enligt vilken 4,65 procent av arbetslöshetsersättningen minskas om den arbetslösa inte kvalificerar sig för tillräcklig betald anställning eller deltar i arbetsförmedlingstjänster under en period på tre månader.
+
- Regeringspartierna driver de arbetslösa genom en lag att bota, trots varningar. Vi accepterar inte att de arbetslösa straffas för att det bara inte finns något jobb. Det är därför som SDP kommer att ändra den aktiva modellen, sade Rinne i en briefing efter omröstningen.
+
*** DISCLAIMER: THIS IS AN AUTOMATED TRANSLATION FROM FINNISH ***
+
Eduskunta on hyväksynyt alkoholilain äänin 124–65. Tyhjää äänesti kaksi ja poissa oli kahdeksan kansanedustajaa. Jo perjantaina eduskunta äänesti, että ruokakaupassa myytävän alkoholin prosenttiraja nousee 5,5:een.
+
Hallituspuolueet ovat aiemmin sopineet, että alkoholiveroa kiristetään 100 miljoonalla eurolla, kun kaupassa myytävien alkoholijuomien enimmäisprosentti nousee.
+
Alkoholilakiin sisältyy alkoholiprosentin lisäksi merkittävä määrä uudistuksia. Uuden alkoholilain myötä ravintola voi esimerkiksi jatkaa anniskelua pelkällä ilmoituksella kello neljään saakka. Ravintola voi olla auki tunnin anniskelun päättymisen jälkeen.
+
Jatkossa ruokakaupassa saa myydä myös muutoin kuin käymisteitse valmistettuja alkoholijuomia eli niin sanottuja limuviinoja. Alkot saavat olla arkisin auki tunnin pidempään eli iltayhdeksään.
+
Eduskunta hyväksyi lisäksi Hannakaisa Heikkisen (kesk.) lausumaehdotuksen, jonka mukaan hallituksen on selvitettävä alkoholin etämyyntiä koskevat säännökset. Etämyynti jäi lakiesityksessä ja sitä koskevassa mietinnössä epäselväksi. Perhe- ja peruspalveluministeri Annika Saarikko (kesk.) on jo kertonut asettavansa työryhmän etämyyntiä selvittämään.
+
– Hallituksen tahdonilmaus on, että emme halua murtaa Alkon monopolia millään riskitekijöillä, joita etämyynti voisi pitää sisällään. Jos Suomessa väkevien alkoholijuomien myynti on rajoitettu
+
, sama koskee myös ulkomaisia toimittajia, Saarikko sanoi perjantaina.
+
Etämyynti tarkoittaa alkoholin hankintaa toisesta EU:n jäsenvaltiosta siten, että myyjä vastaa juomien kuljetuksesta tai kuljetuksen järjestämisestä ostajalle.
+
Eduskunta äänesti myös hallituksen luottamuksesta. Hallitus sai luottamuksen äänin 106–80. Tyhjää äänesti seitsemän kansanedustajaa ja poissa oli kuusi.
+
+
+
Aamupäivän äänestyksissä meni läpi myös esimerkiksi kiistelty työttömyysturvalaki äänin 103–90. Tyhjää äänesti kaksi ja poissa oli neljä kansanedustajaa.
+
Oppositio on vastustanut jyrkästi etenkin lakiin liittyvää aktiivimallia, jonka mukaan työttömyyskorvauksesta nipistetään 4,65 prosenttia, jos työtön ei käy riittävää määrää palkkatyössä tai osallistu työllistymistä edistäviin palveluihin kolmen kuukauden aikana.
+
– Hallituspuolueet runnoivat työttömiä kurittavan lain läpi varoituksista huolimatta. Me emme hyväksy sitä, että työttömiä rangaistaan siitä, että työtä ei yksinkertaisesti ole. Siksi SDP tulee muuttamaan aktiivimallin, Rinne sanoi tiedotteessaan heti äänestyksen jälkeen.